.NET中仅允许唯一项的集合?


102

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<T>可以做到这一点,但是在阅读了文档之后,类似乎只是一个固定的实现(见图)。


4
我不明白您的问题HashSet<T>。MSDN说:“ HashSet <T>类提供高性能的集合操作。集合是一个不包含重复元素且其元素没有特定顺序的集合。”
Daniel Hilgarth'3

5
您能否解释更多为何HashSet<T>不足?
JaredPar'3

@mootinator:Dictionary<K,V>该类保证任何顺序。
路加福音

3
我猜他只是想在尝试添加现有值时引发异常...为此,只需检查从HashSet<T>.Add方法返回的布尔值并在以下情况时引发false...
digEmAll 2011年

2
强烈建议仅重载那些不可变类型。可变的客户通常会使用默认的“参考-平等”条件更好。
Henk Holterman'3

Answers:


204

HashSet<T>是您要寻找的。从MSDN(添加重点):

HashSet<T>类提供高性能的设置操作。集合是不包含重复元素的集合,并且其元素没有特定的顺序。

注意,如果该项目已添加到集合中,则该HashSet<T>.Add(T item)方法返回bool- 如果该物品已经存在。truefalse


9
在这种情况下,T项目应实现IEquatable接口。如果class不继承此接口,则HashSet <T>添加重复的元素。
鲁道夫·德沃拉西克

或代替实现的项目IEquatable,您可以将EqualityComparer<T>实例的(自定义)实现传递给HashSet<T>构造函数。
Sipke Schoorstra

17

HashSet上的扩展方法怎么样?

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

13

HashSet<T>MSDN上的页面:

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

(强调我的)


4

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

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


你是完全正确的;这个问题有点愚蠢。基本上,我一直在寻找在添加重复项时会引发异常的东西(例如Dictionary <TKey,TValue>),但是如上所述,HashSet <T>在重复项添加时返回false。+1,谢谢。
亚当·拉基斯


3

只是加上我的2美分...

如果需要引发ValueExistingException HashSet<T>,则还可以轻松创建集合:

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
Adam Rackis 2011年

0

您可能会研究如下的唯一列表

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"即使添加重复项也只会返回始终

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.