2010-03-23 5 views
18

두 개의 문자열 목록에서 사용자 정의 비교자를 구현하고 .Except() linq 메소드를 사용하여 목록 중 하나가 아닌 것을 가져 오려고합니다. 사용자 정의 비교자를 수행하는 이유는 "퍼지"비교를해야하기 때문입니다. 즉, 한 목록의 한 문자열을 다른 목록의 문자열에 포함 할 수 있습니다.linq 예외 및 사용자 정의 IEqualityComparer

나는 다음과 같은 비교 자

public class ItemFuzzyMatchComparer : IEqualityComparer<string> 
{ 
    bool IEqualityComparer<string>.Equals(string x, string y) 
    { 
     return (x.Contains(y) || y.Contains(x)); 
    } 

    int IEqualityComparer<string>.GetHashCode(string obj) 
    { 
     if (Object.ReferenceEquals(obj, null)) 
      return 0; 
     return obj.GetHashCode(); 
    } 
} 

내가 디버깅

, GetHashCode는() 메소드에 명중 유일한 중단 점을했습니다. Equals()는 절대 건드리지 않습니다. 어떤 아이디어?

+0

그것은 좋은 운동이었다. 제 경우에는'public int GetHashCode (string obj) {return obj.ToLower (GetHashCode();}'질문이 오래되었지만 4 년 후 같은 문제가 발생했습니다. –

답변

18

반환되는 해시 코드가 모두 다르면 동등 함을 비교할 필요가 없습니다.

기본적으로 문제는 해시 및 평등 개념이 매우 다르다는 점입니다. 나는 이것을 어떻게 고칠 것인지 완전히 확신 할 수는 없지만 그렇게 할 때까지는 확실히 작동하지 않을 것입니다.

Equals(a, b)이 true를 반환하면 GetHashCode(a) == GetHashCode(b)이 반환되는지 확인해야합니다. 반전은 사실 일 필요는 없습니다. 해시 충돌은 가능한 한 적게 갖고 싶어하지만 분명히 허용됩니다.

+0

미리 정의 된 객체 (즉, 문자열)의 모음에 대해 맞춤 비교를 적용하려는 경우라고 생각하기 시작했습니다. 커스텀 객체의 콜렉션을 가져야한다면 아마 작동시킬 수있을 것입니다. 나는 그보다 더 좋은 길을 찾아야 할 것 같아. :(다른 사람이 제안을했는지 알기 위해 하루 동안 답을주지 않겠습니다.) – Joe

+0

두 단계로 끝내 었습니다. 들어있는 부분을 사용하여 부분적으로 일치하는 항목의 목록을 생성 한 다음 뒤집어서 수행했습니다. 첫 번째 목록에 대해 해당 하위 집합을 사용하는 것을 제외하고. – Joe

5

Jon은 지적했듯이 해시 코드가 비교 규칙에 따라 두 개의 문자열이 같습니다. 이것은 불행히도 매우 어렵습니다.

Equals(str, "")은 모든 문자열이 빈 문자열과 같음을 의미하는 모든 문자열 str에 대해 true를 반환하므로 결과적으로 모든 문자열은 빈 문자열과 동일한 해시 코드를 가져야합니다.

public class ItemFuzzyMatchComparer : IEqualityComparer<string> { 
    bool IEqualityComparer<string>.Equals(string x, string y) { 
    return (x.Contains(y) || y.Contains(x)); 
    } 
    int IEqualityComparer<string>.GetHashCode(string obj) { 
    if (Object.ReferenceEquals(obj, null)) return 0; 
    return 1; 
    } 
} 

그런 다음 당신이 Except 방법을 사용할 수 있으며 제대로 작동합니다 : 따라서, 제대로 IEqualityComparer을 구현하는 유일한 방법은 항상 같은 해시 코드를 반환하는 것입니다. 유일한 문제는 꽤 비효율적 인 구현을 얻게 될 것이므로 더 나은 성능이 필요하다면 자신 만의 Except을 구현해야 할 수도 있습니다. 그러나 LINQ 구현이 얼마나 비효율적인지 확신 할 수 없으며 실제로 비교 규칙을 효율적으로 구현할 수 있는지 확실하지 않습니다.

1

아마도이 문제는 IEqualityComparer 인터페이스 구현없이 해결 될 수 있습니다. 존 (Jon)과 토마스 (Thomas)는 인터페이스 구현에 관해 좋은 점을 갖고 있으며, 평등은 문제를 정의하지 않는 것처럼 보입니다. 설명에서 Exception 확장을 사용하지 않고이 작업을 수행 할 수 있다고 생각합니다. 대신 먼저 일치 항목을 가져온 다음 예외를 수행하십시오. 이 당신을 위해 일을하는 경우 참조 : 나에게

List<String> listOne = new List<string>(){"hard", "fun", "code", "rocks"}; 
List<String> listTwo = new List<string>(){"fund", "ode", "ard"}; 

var fuzzyMatchList = from str in listOne 
         from sr2 in listTwo 
         where str.Contains(sr2) || sr2.Contains(str) 
         select str; 
var exceptList = listOne.Except(fuzzyMatchList);