[C#] 언제 HashSet <T> 유형을 사용해야합니까?

HashSet<T>유형을 탐색하고 있지만 컬렉션에서 어디에 있는지 이해하지 못합니다.

그것을 대체하기 위해 그것을 사용할 수 있습니까 List<T>? 나는 a의 성능 HashSet<T>이 더 뛰어나다 고 생각 하지만 그 요소에 대한 개별 액세스를 볼 수 없었습니다.

열거 전용입니까?



답변

중요한 것은 HashSet<T>이름에 바로 있습니다 : 그것은 집합 입니다. 단일 세트로 수행 할 수있는 유일한 작업은 멤버가 무엇인지 설정하고 항목이 멤버인지 여부를 확인하는 것입니다.

단일 요소 (예 :)를 검색 할 수 있는지 묻는 set[45]것은 세트의 개념을 오해하고 있습니다. 세트의 45 번째 요소와 같은 것은 없습니다. 세트의 품목에는 주문이 없습니다. {1, 2, 3} 및 {2, 3, 1} 세트는 멤버십이 동일하므로 멤버십이 중요하므로 모든 점에서 동일합니다.

세트를 반복하는 HashSet<T>것은 세트의 아이템에 순서를 부과하기 때문에 다소 위험합니다 . 그 순서는 실제로 집합의 속성이 아닙니다. 당신은 그것에 의존해서는 안됩니다. 컬렉션의 항목 순서가 중요한 경우 해당 컬렉션은 설정되지 않습니다.

세트는 실제로 제한되며 고유 한 멤버로 구성됩니다. 반면에, 그들은 정말 빠릅니다.


답변

다음은 내가 사용하는 실제 예입니다 HashSet<string>.

UnrealScript 파일 용 구문 강조 표시의 일부는 Doxygen 스타일 설명강조 표시 하는 새로운 기능입니다 . 회색 (유효) 또는 빨간색 (유효)으로 표시할지 결정하기 위해 @또는 \명령이 유효한지 알 수 있어야합니다 . 나는이 HashSet<string>내가 공격 할 때마다 그래서, 모든 유효한 명령을 @xxx렉서의 토큰을, 내가 사용하는 validCommands.Contains(tokenText)내 O (1) 유효 기간 확인한다. 유효한 명령 집합 에 명령이 존재 하는 것 외에는 아무것도 신경 쓰지 않습니다 . 내가 직면 한 대안을 살펴 보겠습니다.

  • Dictionary<string, ?>: 값에 어떤 유형을 사용합니까? 방금 사용하기 때문에 값이 의미가 없습니다 ContainsKey. 참고 : .NET 3.0 이전에는 O (1) 조회를위한 유일한 선택 HashSet<T>이었습니다. 3.0에 추가 ISet<T>되고 4.0 에 구현 되도록 확장되었습니다 .
  • List<string>: 목록을 정렬 상태로 유지하면 BinarySearchO (log n) 인 (위에서 언급 한 사실을 보지 못함)을 사용할 수 있습니다 . 그러나 유효한 명령 목록은 절대 바뀌지 않는 고정 목록이므로 간단하지 않습니다.
  • string[]: 다시, Array.BinarySearchO (log n) 성능을 제공합니다. 목록이 짧으면 이것이 가장 성능이 좋은 옵션 일 수 있습니다. 항상보다 적은 공간 오버 헤드가 HashSet, Dictionary또는 List. 로도 BinarySearch큰 세트의 경우 더 빠르지는 않지만 작은 세트의 경우 실험 해 볼 가치가 있습니다. 광산에는 수백 개의 항목이 있으므로 이것을 전달했습니다.

답변

A는 HashSet<T>구현 ICollection<T>인터페이스 :

public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
    // Methods
    void Add(T item);
    void Clear();
    bool Contains(T item);
    void CopyTo(T[] array, int arrayIndex);
    bool Remove(T item);

    // Properties
   int Count { get; }
   bool IsReadOnly { get; }
}

List<T>구현 IList<T>확장,ICollection<T>

public interface IList<T> : ICollection<T>
{
    // Methods
    int IndexOf(T item);
    void Insert(int index, T item);
    void RemoveAt(int index);

    // Properties
    T this[int index] { get; set; }
}

HashSet은 내부적으로 해시 테이블을 통해 구현 된 의미를 설정했습니다.

집합은 중복 요소가없고 특정 순서가 아닌 컬렉션입니다.

인덱스 / 포지션 /리스트 동작을 잃으면 HashSet이 얻는 이점

HashSet에서 항목을 추가하고 검색하는 것은 항상 인덱서를 통하지 않고 객체 자체에 의해 이루어지며 O (1) 연산에 가깝습니다 (목록은 O (1) 추가, O (1)은 색인으로 검색, O (n) 찾기 /없애다).

Dictionary<TKey,TValue>키를 값으로 추가 / 제거하고 사전 값 자체를 무시하는 것만으로 HashSet의 동작을 비교할 수 있습니다 . 딕셔너리의 키가 중복 된 값을 가지지 않기를 기대할 수 있습니다. 이것이 바로 “설정”부분입니다.


답변

성능은 목록보다 HashSet을 선택하는 나쁜 이유입니다. 대신 의도를 더 잘 포착하는 것은 무엇입니까? 순서가 중요한 경우 Set (또는 HashSet)이 종료됩니다. 마찬가지로 복제가 허용되는 경우. 그러나 주문에 신경 쓰지 않는 상황이 많으며 복제본이 없을 것입니다. 그러면 세트를 원할 때입니다.


답변

HashSet은 해싱으로 구현 된 집합 입니다. 집합은 중복 요소가없는 값의 모음입니다. 집합의 값은 일반적으로 순서가 없습니다. 따라서, 세트를 사용하여 목록을 대체 할 수 없습니다 (처음에 세트를 사용해야하지 않는 한).

어떤 세트가 좋은지 궁금해하는 경우 : 분명히 복제본을 없애고 싶은 곳. 약간의 예를 들어, 소프트웨어 프로젝트의 10.000 개정 목록이 있고 그 프로젝트에 얼마나 많은 사람들이 기여했는지 알고 싶다고 가정 해 봅시다. a를 사용하여 Set<string>개정 목록을 반복하고 각 개정의 작성자를 세트에 추가 할 수 있습니다 . 반복을 마치면 세트의 크기가 원하는 답입니다.


답변

HashSet은 IEnumerable 컬렉션에서 중복 요소를 제거하는 데 사용됩니다. 예를 들어

List<string> duplicatedEnumrableStrings = new List<string> {"abc", "ghjr", "abc", "abc", "yre", "obm", "ghir", "qwrt", "abc", "vyeu"};
HashSet<string> uniqueStrings = new HashSet(duplicatedEnumrableStrings);

해당 코드가 실행 된 후 uniqueStrings는 { “abc”, “ghjr”, “yre”, “obm”, “qwrt”, “vyeu”}를 보유합니다.


답변

아마도 해시 셋에 대한 가장 일반적인 용도는 포함에 대한 검사가 O ( n) (그리고 O (log n) 인 정렬 세트). 따라서 항목을 일부 목록에 포함했는지 여부를 많이 확인하면 성능 향상이 될 수 있습니다. 그것들을 반복하는 것만으로도 큰 차이는 없습니다 (목록과 해시 세트가 항목을 추가 할 때 약간 더 많은 오버 헤드가있는 것과 같이 전체 세트를 반복하는 것은 O (n)입니다).

그리고 아니요, 세트는 순서가 없기 때문에 어쨌든 의미가없는 세트를 색인 할 수 없습니다. 일부 항목을 추가하면 세트는 첫 번째 항목과 두 번째 등을 기억하지 않습니다.