【问题标题】:Collection that allows only unique items in .NET?仅允许 .NET 中唯一项目的集合?
【发布时间】:2011-07-06 16:18:42
【问题描述】:

C# 中是否存在不允许您向其中添加重复项的集合?例如,用愚蠢的类

public class Customer {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }

    public override int GetHashCode() {
        return (FirstName + LastName + Address).GetHashCode();
    }

    public override bool Equals(object obj) {
        Customer C = obj as Customer;
        return C != null && String.Equals(this.FirstName, C.FirstName) && String.Equals(this.LastName, C.LastName) && String.Equals(this.Address, C.Address);
    }
}

以下代码将(显然)抛出异常:

Customer Adam = new Customer { Address = "A", FirstName = "Adam", LastName = "" };
Customer AdamDup = new Customer { Address = "A", FirstName = "Adam", LastName = "" };

Dictionary<Customer, bool> CustomerHash = new Dictionary<Customer, bool>();
CustomerHash.Add(Adam, true);
CustomerHash.Add(AdamDup, true);

但是有没有一个类可以同样保证唯一性,但没有 KeyValuePairs?我认为HashSet&lt;T&gt; 会这样做,但在阅读了文档后,似乎该类只是一个集合实现(go figure)。

【问题讨论】:

  • 我不明白您对HashSet&lt;T&gt; 的问题。 MSDN 说“HashSet 类提供了高性能的集合操作。集合是不包含重复元素的集合,其元素没有特定的顺序。”
  • 你能解释一下为什么HashSet&lt;T&gt;不够吗?
  • @mootinator:Dictionary&lt;K,V&gt;保证任何顺序。
  • 我猜他只是想在您尝试添加现有值时抛出异常...为此,只需检查从HashSet&lt;T&gt;.Add 方法返回的布尔值并在false 时抛出。 ..
  • 强烈建议只重载那些 immutable 类型。使用默认的 Reference-equality 时,可变客户通常会更好。

标签: c# set hashset


【解决方案1】:

HashSet&lt;T&gt; 是您正在寻找的。来自MSDN(强调):

HashSet&lt;T&gt; 类提供高性能的集合操作。集合是不包含重复元素且其元素没有特定顺序的集合。

注意HashSet&lt;T&gt;.Add(T item) method 返回一个bool -- true 如果项目被添加到集合中; false 如果该项目已经存在。

【讨论】:

  • 这种情况下的T项应该实现IEquatable接口。如果类没有继承这个接口,HashSet会添加重复元素。
  • 或者代替实现IEquatable的项目,您可以将EqualityComparer&lt;T&gt;实例的(自定义)实现传递给HashSet&lt;T&gt;构造函数。
【解决方案2】:

HashSet 上的扩展方法怎么样?

public static void AddOrThrow<T>(this HashSet<T> hash, T item)
{
    if (!hash.Add(item))
        throw new ValueExistingException();
}

【讨论】:

    【解决方案3】:

    来自 MSDN 上的HashSet&lt;T&gt; 页面:

    HashSet(Of T) 类提供高性能的集合操作。 集合是不包含重复元素的集合,其元素没有特定顺序。

    (强调我的)

    【讨论】:

      【解决方案4】:

      如果您只需要确保元素的唯一性,那么 HashSet 就是您所需要的。

      当您说“只是一个集合实现”时,您是什么意思?集合(根据定义)是不保存元素顺序的唯一元素的集合。

      【讨论】:

      • 你完全正确;这个问题有点愚蠢。基本上,我一直在寻找在添加重复项时会引发异常的东西(如 Dictionary),但如前所述,HashSet 在重复添加时返回 false。 +1,谢谢。
      【解决方案5】:

      只是为了加我的 2 美分...

      如果您需要抛出 ValueExistingException HashSet&lt;T&gt;,您也可以轻松创建您的集合:

      public class ThrowingHashSet<T> : ICollection<T>
      {
          private HashSet<T> innerHash = new HashSet<T>();
      
          public void Add(T item)
          {
              if (!innerHash.Add(item))
                  throw new ValueExistingException();
          }
      
          public void Clear()
          {
              innerHash.Clear();
          }
      
          public bool Contains(T item)
          {
              return innerHash.Contains(item);
          }
      
          public void CopyTo(T[] array, int arrayIndex)
          {
              innerHash.CopyTo(array, arrayIndex);
          }
      
          public int Count
          {
              get { return innerHash.Count; }
          }
      
          public bool IsReadOnly
          {
              get { return false; }
          }
      
          public bool Remove(T item)
          {
              return innerHash.Remove(item);
          }
      
          public IEnumerator<T> GetEnumerator()
          {
              return innerHash.GetEnumerator();
          }
      
          System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
          {
              return this.GetEnumerator();
          }
      }
      

      这可能很有用,例如,如果您在很多地方都需要它...

      【讨论】:

      • 当然。我想知道是否有任何内置功能,但谢谢 +1
      【解决方案6】:

      你可以试试HashSet&lt;T&gt;

      【讨论】:

        【解决方案7】:

        您可以查看如下的唯一列表

        public class UniqueList<T>
        {
            public List<T> List
            {
                get;
                private set;
            }
            List<T> _internalList;
        
            public static UniqueList<T> NewList
            {
                get
                {
                    return new UniqueList<T>();
                }
            }
        
            private UniqueList()
            {            
                _internalList = new List<T>();
                List = new List<T>();
            }
        
            public void Add(T value)
            {
                List.Clear();
                _internalList.Add(value);
                List.AddRange(_internalList.Distinct());
                //return List;
            }
        
            public void Add(params T[] values)
            {
                List.Clear();
                _internalList.AddRange(values);
                List.AddRange(_internalList.Distinct());
               // return List;
            }
        
            public bool Has(T value)
            {
                return List.Contains(value);
            }
        }
        

        你可以像下面这样使用它

        var uniquelist = UniqueList<string>.NewList;
        uniquelist.Add("abc","def","ghi","jkl","mno");
        uniquelist.Add("abc","jkl");
        var _myList = uniquelist.List;
        

        即使添加了重复项,也只会返回"abc","def","ghi","jkl","mno"

        【讨论】:

          猜你喜欢
          • 2012-05-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-15
          • 2011-03-05
          • 2015-07-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多