Lambda에 의해 정의 된 사용자 정의 iequalitycompare가있는 해시 세트 생성자?
-
22-08-2019 - |
문제
현재 HashSet<T>
평등 비교를 정의 할 수있는 생성자는 HashSet<T>(IEqualityComparer<T> comparer)
건설자. 나는이 평등을 람다로 정의하고 싶습니다.
나는 찾았다 이 블로그 게시물 이로 인해 Lambda를 통해 비교기를 생성 할 수있는 클래스가 만들어졌으며 예를 들어 ()을 예를 들어 연장 메소드 로이 클래스의 구성을 숨 깁니다.
이제 나는 똑같이하고 생성자와 함께하고 싶습니다. 확장 방법을 통해 생성자를 만들 수 있습니까? 아니면 어떻게 든 HashSet<T>(Func<T,T,int> comparer)
?
--업데이트--
명확성을 위해, 이것은 내가 달성하려는 것의 프리 핸드 버전입니다.
HashSet<FileInfo> resultFiles = new HashSet<FileInfo>(
srcPath.GetFiles(),
new LambdaComparer<FileInfo>(
(f1, f2) => f1.Name.SubString(10).Equals(f2.Name.SubString(10))));
또는 더 이상적으로
HashSet<FileInfo> resultFiles = new HashSet<FileInfo>(
srcPath.GetFiles(),
(f1, f2) => f1.Name.SubString(10).Equals(f2.Name.SubString(10)));
해결책
아니요, 생성자를 추가 할 수 없습니다 (확장 방법이 있더라도).
당신이 Func<T,T,int>
an IEqualityComparer<T>
(블로그 게시물을 인용 할 수 있다면 해당 블로그 게시물을 읽는 데 관심이 있습니다) - 그러면 가장 가까운 것은 아마도 다음과 같습니다.
public static class HashSet {
public static HashSet<T> Create<T>(Func<T, T, int> func) {
IEqualityComparer<T> comparer = YourMagicFunction(func);
return new HashSet<T>(comparer);
}
}
하지만; 나는 당신이 평등을 위해 람다로 할 수있는 일에 대해 모호합니다 ... 당신은 표현할 두 가지 개념, 즉 해싱과 진정한 평등이 있습니다. 당신의 람다는 어떻게 생겼습니까? 아동 속성을 연기하려고한다면 아마도 Func<T,TValue>
속성을 선택하고 사용합니다 EqualityComparer<TValue>.Default
내부적 ... 같은 것 :
class Person {
public string Name { get; set; }
static void Main() {
HashSet<Person> people = HashSetHelper<Person>.Create(p => p.Name);
people.Add(new Person { Name = "Fred" });
people.Add(new Person { Name = "Jo" });
people.Add(new Person { Name = "Fred" });
Console.WriteLine(people.Count);
}
}
public static class HashSetHelper<T> {
class Wrapper<TValue> : IEqualityComparer<T> {
private readonly Func<T, TValue> func;
private readonly IEqualityComparer<TValue> comparer;
public Wrapper(Func<T, TValue> func,
IEqualityComparer<TValue> comparer) {
this.func = func;
this.comparer = comparer ?? EqualityComparer<TValue>.Default;
}
public bool Equals(T x, T y) {
return comparer.Equals(func(x), func(y));
}
public int GetHashCode(T obj) {
return comparer.GetHashCode(func(obj));
}
}
public static HashSet<T> Create<TValue>(Func<T, TValue> func) {
return new HashSet<T>(new Wrapper<TValue>(func, null));
}
public static HashSet<T> Create<TValue>(Func<T, TValue> func,
IEqualityComparer<TValue> comparer)
{
return new HashSet<T>(new Wrapper<TValue>(func, comparer));
}
}
다른 팁
마크가 옳다. 단일 람다가 평등과 gethashcode에 필요한 정보를 표현하는 간단한 방법은 없습니다. 그리고 "동일한"요소에 대해 다른 해시를 반환하는 gethashcode를 제공하면 잘못된 동작이 발생합니다.
내 타협 구현은 다음과 같습니다. 그것은 모든 일반적인 기능 (Marc와 같이 INT를 설명하지 않았기 때문에 INT를 무시 했음)을 허용하며, 이는 (계약을 준수한다는 점에서), 매우 비효율적 인 행동을 제공 할 것입니다.
귀하의 요구를 충족시키는 실제 iqualitycomparer를 고수하는 것이 좋습니다. 그러나 부끄러운 C#은 익명의 내부 클래스를 지원하지 않습니다.
public static class HashSetDelegate
{
public static HashSet<T> Create<T>(Func<T, T, bool> func)
{
return new HashSet<T>(new FuncIEqualityComparerAdapter<T>(func));
}
private class FuncIEqualityComparerAdapter<U> : IEqualityComparer<U>
{
private Func<U, U, bool> func;
public FuncIEqualityComparerAdapter(Func<U, U, bool> func)
{
this.func = func;
}
public bool Equals(U a, U b)
{
return func(a, b);
}
public int GetHashCode(U obj)
{
return 0;
}
}
}
public class HashSetTest
{
public static void Main()
{
HashSet<string> s = HashSetDelegate.Create((string a, string b) => string.Compare(a, b, true) == 0);
}
}