HashSet <T>와 List <T>의 차이점은 무엇입니까?


156

.NET HashSet<T>과 의 차이점을 설명 할 수 있습니까 List<T>?

어쩌면 어떤 경우에 HashSet<T>선호 해야하는지 예를 통해 설명 할 수 List<T>있습니까?



en.wikipedia.org/wiki/Hash_tableen.wikipedia.org/wiki/Dynamic_array 의 Wikipedia 기사를 참조하십시오 .
mqp

관련 성능을 참조 HashSet의 - 대 - 목록 - 성능
nawfal

답변:


213

리스트와 달리 <> ...

  1. HashSet은 중복 멤버가없는 목록입니다.

  2. HashSet은 고유 한 항목 만 포함하도록 제한되므로 내부 구조는 검색에 최적화되어 (목록과 비교) 훨씬 빠릅니다.

  3. HashSet에 추가하면 부울이 반환됩니다. Set에 이미 존재하여 추가에 실패하면 false

  4. Set : Union / Intersection / IsSubsetOf 등에 대해 수학적 세트 연산을 수행 할 수 있습니다.

  5. HashSet은 IList 만 구현하지 않습니다. ICollection

  6. HashSet에는 인덱스를 사용할 수 없으며 열거 자만 사용할 수 있습니다.

HashSet을 사용하는 주된 이유는 Set 작업 수행에 관심이있는 것입니다.

주어진 2 세트 : hashSet1 및 hashSet2

 //returns a list of distinct items in both sets
 HashSet set3 = set1.Union( set2 );

LINQ를 사용하는 동등한 작업과 비교하여 날아갑니다. 쓰는 것이 더 깔끔합니다!


IDK, Union방법에 문제가있었습니다 . 나는 UnionWith대신 사용 했다.
사용자

2
"HashedSet를 사용하는 주된 이유는 Set 작업 수행에 관심이있는 경우입니다."
LCJ

12
사실, 컬렉션을 "가방 아이템"으로 취급 할 수있는 경우 HashSets가 적합하다는 답변을 선호합니다. 격리 작업은 자주 확인하지 않습니다. 고유 항목 세트 (예 : 코드)가 있고 억제 여부를 확인해야 할 때마다 HashSet이 편리합니다.
ThunderGr

좋은 대답입니다. 몇 가지 성능 특성 차이도 추가하고 싶습니다.
nawfal

1
질문 : 주된 이유는 중복 된 항목이 없다는 확신이없는 것입니까?
Andrea Scarafoni

54

더 정확하게는 예제를 통해 설명해 드리겠습니다.

다음 예제와 같이 HashSet을 사용할 수 없습니다.

HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
    Console.WriteLine(hashSet1[i]);

hashSet1[i] 오류가 발생합니다.

'System.Collections.Generic.HashSet'형식의 식에 []를 사용하여 인덱싱을 적용 할 수 없습니다.

foreach 문을 사용할 수 있습니다.

foreach (var item in hashSet1)
    Console.WriteLine(item);

List를 사용하면이 작업을 수행 할 수 있고 HashSet에 항목을 추가하는 동안 항목을 포함하는지 여부를 확인할 수있는 동안 중복 된 항목을 HashSet에 추가 할 수 없습니다.

HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
   Console.WriteLine("'1' is successfully added to hashSet1!");
else
   Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");

HashSet의이 같은 몇 가지 유용한 기능이있다 IntersectWith, UnionWith, IsProperSubsetOf, ExceptWith, SymmetricExceptWith

IsProperSubsetOf:

HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
    Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
    Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");

UnionWith:

HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8

IntersectWith:

HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8

ExceptWith :

 HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
 HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
 hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6

SymmetricExceptWith :

 HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
 HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
 hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6

그건 그렇고, 순서는 HashSets에서 유지되지 않습니다. 이 예에서는 마지막에 "2"요소를 추가했지만 두 번째 순서입니다.

HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1");    // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2");    // 3, 2 ,8, 1

51

A HashSet<T>O(1)봉쇄 를 찾아 보기 위해 고안된 클래스입니다 (즉,이 컬렉션에 특정 개체가 포함되어 있고 답을 빨리 알려주세요).

A List<T>O(1)동적으로 성장할 수있는 것 (동적 배열을 생각할 수있는 것)보다 무작위로 액세스 할 수있는 모음을 제공하도록 설계된 클래스입니다 . 당신의 봉쇄를 테스트 할 수 있습니다 O(n)(목록이 정렬되어 있지 않으면, 다음에 이진 검색 할 수있는 시간 O(log n)시간).

어쩌면 어떤 경우에 HashSet<T>선호 해야하는지에 대한 예를 들어 설명 할 수 있습니다.List<T>

당신의 봉쇄를 테스트 할 때 O(1).


목록이 정렬 된 경우 O (log n)입니다. 결국 정렬되지 않은 목록에서 조회하는 것보다 빠릅니다.
Andrei

20

List<T>원하는 경우를 사용하십시오 .

  • 항목 모음을 특정 순서로 저장하십시오.

항목 자체의 값이 아닌 원하는 항목의 색인을 알고있는 경우 검색은 O(1)입니다. 색인을 모르는 O(n)경우 정렬되지 않은 컬렉션의 경우 항목을 찾는 데 시간이 더 걸립니다 .

Hashset<T>원하는 경우를 사용하십시오 .

  • 컬렉션에 특정 개체가 포함되어 있는지 빠르게 확인할 수 있습니다.

찾으려는 것의 이름을 알고 있다면 조회는 O(1)( '해시'부분입니다). 그것은 주문과 같은 순서를 유지하지 않으며 List<T>중복을 저장할 수 없습니다 (중복을 추가해도 아무런 영향을 미치지 않습니다. 그것은 '설정'부분입니다).

Hashset<T>Scrabble 게임에서 사용 된 단어가 영어 (또는 다른 언어)로 유효한 단어인지 확인하려는 경우 a를 사용하는 경우를 예로들 수 있습니다. 그러한 게임의 온라인 버전의 모든 인스턴스에서 사용할 웹 서비스를 구축하려는 경우 더 좋습니다.

A List<T>는 플레이어 점수를 추적하기 위해 스코어 보드를 생성하기위한 좋은 데이터 구조입니다.


15

목록은 순서가 지정된 목록입니다. 그것은

  • 정수 인덱스로 액세스
  • 중복을 포함 할 수 있습니다
  • 예측 가능한 순서가있다

HashSet은 세트입니다. 그것:

  • 중복 항목을 차단할 수 있습니다 ( Add (T) 참조 ).
  • 세트 내의 품목 순서를 보장하지 않습니다
  • IntersectWith, IsProperSubsetOf, UnionWith 와 같은 집합에 대해 예상되는 작업이 있습니다 .

목록은 항목을 추가, 삽입 및 제거 할 수있는 배열과 마찬가지로 컬렉션에 액세스하려는 경우에 더 적합합니다. HashSet은 컬렉션이 중요하지 않은 아이템의 "가방"처럼 취급하거나 IntersectWith 또는 UnionWith와 같은 연산을 사용하여 다른 세트와 비교하려는 경우 더 나은 선택입니다.



3

목록은 배열과 달리 항목을 추가 및 제거 할 수있는 유형 T의 정렬 된 개체 모음입니다.

저장된 순서대로 멤버를 참조하려는 목록을 사용하고 항목 자체가 아닌 위치로 멤버에 액세스합니다.

HashSet은 항목 자체가 값뿐만 아니라 키라는 사전과 같습니다. 순서는 보장되지 않습니다.

개체가 컬렉션에 있는지 확인하려는 HashSet을 사용합니다.


1
명확히하기 위해 다른 사람이 언뜻보기에 잘못 읽은 경우- List주문을 유지하지만 (항목이 추가 된 시점) 항목을 자동으로 정렬하지는 않습니다. 에 전화 .Sort하거나을 사용해야합니다 SortedList.
drzaus

1

이러한 데이터 구조를 데이터 기반 개발에서 실제 사용에 적용하기로 결정한 경우 HashSet은 데이터 정리 및 마이그레이션을 위해 데이터 어댑터 소스에 대한 복제 테스트에 매우 유용합니다.

또한 DataAnnotations 클래스를 사용하는 경우 클래스 속성에 키 로직을 구현하고 HashSet을 사용하여 자연 인덱스 (클러스터 또는 클러스터되지 않음)를 효과적으로 제어 할 수 있습니다.이 경우 List 구현에서는 매우 어렵습니다.

목록을 사용하는 강력한 옵션은 DropDownList Helper를 위해 MVC보기에 클래스 목록을 전송하고 WebApi를 통해 JSON 구조로 전송하는 것과 같이보기 모델에서 여러 매체의 제네릭을 구현하는 것입니다. 이 목록은 일반적인 클래스 수집 로직을 허용하고 단일 매체를 다른 매체로 계산하는 접근 방식과 같은보다 "인터페이스"에 대한 유연성을 유지합니다.

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