program story

HashSet 만들기

inputbox 2020. 12. 4. 08:10
반응형

HashSet 만들기 대소 문자를 구분하지 않음


HashSet 매개 변수가있는 메서드가 있습니다. 그리고 그 안에 대소 문자를 구분하지 않는 포함을 수행해야합니다.

public void DoSomething(HashSet<string> set, string item)
{
    var x = set.Contains(item);
    ... 
}

기존 HashSet을 대소 문자를 구분하지 않게 만드는 방법이 있습니까 (새로 만들지 마십시오)?

최고의 성능을 가진 솔루션을 찾고 있습니다.

편집하다

포함은 여러 번 호출 할 수 있습니다. 따라서 IEnumerable 확장은 네이티브 HashSet Contains 메서드보다 성능이 낮기 때문에 허용되지 않습니다.

해결책

내 질문에 대한 대답은 아니오이므로 불가능하므로 다음 방법을 만들고 사용했습니다.

public HashSet<string> EnsureCaseInsensitive(HashSet<string> set)
{
    return set.Comparer == StringComparer.OrdinalIgnoreCase
           ? set
           : new HashSet<string>(set, StringComparer.OrdinalIgnoreCase);
}

HashSet<T>생성자는 사용자 정의에 건네 줄 수가 있습니다 과부하가 있습니다 IEqualityComparer<string>. 이 중 일부는 이미 정적 StringComparer클래스 에 정의되어 있으며 일부는 대소 문자를 무시합니다. 예를 들면 :

var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
set.Add("john");
Debug.Assert(set.Contains("JohN"));

.NET Framework를 생성 할 때이 변경을 수행해야합니다 HashSet<T>. 하나가 존재하면 IEqualityComparer<T>사용 중인 것을 변경할 수 없습니다 .


(당신이 어떤 전달하지 않는 경우 그냥 그래서 당신은 기본적으로 알고 IEqualityComparer<T>받는 HashSet<T>생성자)이 사용하는 EqualityComparer<T>.Default대신.


편집하다

내 답변을 게시 한 후 질문이 변경된 것 같습니다. 당신이 사건을해야 할 경우 를 구분 기존의 경우 검색 민감 HashSet<string> , 당신은 선형 검색을 수행해야합니다 :

set.Any(s => string.Equals(s, item, StringComparison.OrdinalIgnoreCase));

이 문제를 해결할 방법이 없습니다.


대소 문자를 구분하지 않는 방식으로 동작하도록 대소 문자를 구분하는 HashSet (또는 사전)을 마술처럼 만들 수 없습니다.

HashSet대소 문자를 구분하지 않기 위해 수신 의존 할 수 없다면 함수 내에서 하나를 다시 만들어야합니다 .

가장 간결한 코드- 기존 집합의 생성자사용 합니다.

var insensitive = new HashSet<string>(
   set, StringComparer.InvariantCultureIgnoreCase);

복사 HashSet는 모든 항목을 살펴 보는 것만 큼 비싸므로 함수가 검색 만 수행하는 경우 모든 항목을 반복하는 것이 더 저렴합니다 (O (n)). 함수가 대소 문자를 구분하지 않는 단일 검색을 위해 여러 번 호출 된 경우 HashSet대신 적절 하게 전달해야 합니다.


HashSet빠르게 해시 기능과 평등의 비교에 따라 요소를 찾을 수 있도록 설계되었습니다. 당신이 요구하는 것은 실제로 "다른"조건과 일치하는 요소를 찾는 것입니다. 비교 용으로 Set<Person>만 사용 하는 객체가 Person.Name있고 주어진 값이있는 요소를 찾아야 한다고 가정 해보 십시오 Person.Age.

요점은 일치하는 요소를 찾기 위해 세트의 내용을 반복해야한다는 것입니다. 이 작업을 자주 수행하려는 경우 대소 문자를 구분하지 않는 비교기를 사용하는 경우 다른 세트를 만들 수 있지만이 그림자 세트가 원본과 동기화되어 있는지 확인해야합니다.

지금까지의 답변은 본질적으로 위의 변형이며, 근본적인 문제를 명확히하기 위해 이것을 추가하려고 생각했습니다.


이 확장 방법이 있다고 가정합니다.

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
    return new HashSet<T>(source);
}

이것을 사용할 수 있습니다.

set = set.Select(n => n.ToLowerInvariant()).ToHashSet();

또는 다음과 같이 할 수 있습니다.

set = new HashSet(set, StringComparer.OrdinalIgnoreCase); 
//or InvariantCultureIgnoreCase or CurrentCultureIgnoreCase

의 생성자는 동등성이 결정되는 방식을 재정 HashSet할 수있는 대안 IEqualityComparer취할 수 있습니다. 여기 에서 생성자 목록을 참조 하십시오 .

The class StringComparer contains a bunch of static instances of IEqualityComparers for strings. Particularly, you're probably interested in StringComparer.OrdinalIgnoreCase. Here is the documentation of StringComparer.

Note that another constructor takes in an IEnumerable, so you can construct a new HashSet from your old one, but with the IEqualityComparer.

So, all together, you want to convert your HashSet as follows:

var myNewHashSet = new HashSet(myOldHashSet, StringComparer.OrdinalIgnoreCase);

If you want to leave the original, case-sensitive version in place, you could just query it with linq with case insensitivity:

var contains = set.Any(a => a.Equals(item, StringComparison.InvariantCultureIgnoreCase));

You can now use

set.Contains(item, StringComparer.OrdinalIgnoreCase);

without needing to re-create you HashSet

참고URL : https://stackoverflow.com/questions/16922435/make-hashsetstring-case-insensitive

반응형