.NETで一意のアイテムのみを許可するコレクション?


103

重複するアイテムを追加できない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、2011年

5
なぜHashSet<T>不十分なのか、もう少し説明してもらえますか?
JaredPar 2011年

@mootinator:Dictionary<K,V>クラスいかなる種類の順序も保証しません。
LukeH、2011年

3
既存の値を追加しようとしたときに例外をスローするだけだと思います...これを行うには、HashSet<T>.Addメソッドから返されたブール値を確認して、次の場合にスローしfalseます...
digEmAll

2
また、不変タイプのみをオーバーロードすることを強くお勧めします。変更可能なCustomerは通常、デフォルトのReference-equalityを使用するほうが公平です。
Henk Holterman、2011年

回答:


205

HashSet<T>あなたが探しているものです。MSDNから(強調を追加):

このHashSet<T>クラスは、高性能な集合演算を提供します。セットは、重複する要素含まないコレクションであり、その要素には特定の順序はありません。

なお、HashSet<T>.Add(T item)この方法は、返しbool- trueアイテムがコレクションに追加された場合。falseアイテムがすでに存在していた場合。


9
この場合のTアイテムはIEquatableインターフェイスを実装する必要があります。クラスがこのインターフェイスを継承しない場合、HashSet <T>は重複する要素を追加します。
ルドルフドヴォラセク2018年

または、item implementingの代わりに、インスタンスの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、ありがとうございます。
Adam Rackis、2011年


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
アダムラッキス

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"重複が追加された場合でも常に返されます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.