.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

5
HashSet<T>부족한 이유를 더 설명해 주 시겠습니까?
JaredPar 2011 년

@mootinator : Dictionary<K,V>수업 어떤 종류의 순서도 보장 하지 않습니다 .
LukeH 2011 년

3
기존 값을 추가하려고 할 때 예외를 던지고 싶어하는 것 같습니다. 이렇게하려면 HashSet<T>.Add메서드 에서 반환 된 bool 값을 확인하고 다음 과 같은 경우에 던집니다 false. ...
digEmAll 2011 년

2
또한 불변 유형에 대해서만 오버로드하는 것이 좋습니다 . 변경 가능한 고객은 일반적으로 기본 Reference-equality가 더 좋습니다.
Henk Holterman 2011 년

답변:


205

HashSet<T>당신이 찾고있는 것입니다. 에서 MSDN (강조는 추가) :

HashSet<T>클래스는 고성능 집합 작업을 제공합니다. 집합은 중복 요소가없고 요소가 특정 순서 가 아닌 컬렉션입니다 .

HashSet<T>.Add(T item)메서드 는 항목이 컬렉션에 추가 된 경우 bool-를 반환합니다 true. false항목이 이미있는 경우.


9
이 경우 T 항목은 IEquatable 인터페이스를 구현해야합니다. 클래스가이 인터페이스를 상속하지 않는 경우 HashSet <T>는 중복 요소를 추가합니다.
Rudolf Dvoracek

또는 구현 항목 대신 인스턴스 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
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"중복이 추가 되어도 항상 반환 됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.