19

文字列の 2 つのリストにカスタム比較子を実装し、.Except() linq メソッドを使用して、リストの 1 つではないものを取得しようとしています。カスタム比較子を使用する理由は、"あいまい" な比較を行う必要があるためです。つまり、1 つのリストの 1 つの文字列を別のリストの文字列内に埋め込むことができます。

次の比較子を作成しました

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() は決して触れられません。何か案は?

4

3 に答える 3

17

返されたすべてのハッシュ コードが異なる場合、等しいかどうかを比較する必要はありません。

基本的に問題は、ハッシュと等価の概念が大きく異なることです。これをどのように修正するかは完全にはわかりませんが、修正するまでは確実に機能しません。

Equals(a, b)true を返す場合は、GetHashCode(a) == GetHashCode(b). (逆は真である必要はありません。ハッシュの衝突は許容されますが、可能な限り少なくしたいのは明らかです。)

于 2010-03-23T15:13:51.880 に答える
6

Jon が指摘したように、2 つの文字列のハッシュ コードが等しいことを確認する必要があります (比較規則に従って)。これは残念ながらかなり難しいです。

問題を示すために、Equals(str, "")はすべての文字列に対して true を返しますstr。これは基本的に、すべての文字列が空の文字列と等しいことを意味し、結果として、すべての文字列が空の文字列と同じハッシュ コードを持つ必要があります。したがって、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 1; 
  } 
}

その後、メソッドを使用でき、Except正しく動作します。唯一の問題は、(おそらく) 非常に非効率的な実装になることです。そのため、より良いパフォーマンスが必要な場合は、独自のExcept. ただし、LINQ の実装がどの程度非効率になるかは正確にはわかりません。また、比較ルールの効率的な実装が実際に可能かどうかもわかりません。

于 2010-03-23T16:23:13.707 に答える
1

おそらく、この問題は IEqualityComparer インターフェイスの実装なしで解決できるでしょう。Jon と Thomas は、そのインターフェイスの実装について良い点を持っており、平等があなたの問題を定義していないようです。あなたの説明から、比較中に Except 拡張機能を使用せずにこれを行うことができると思います。代わりに、最初に一致を取得してから、例外を実行します。これがあなたのために仕事をするかどうか見てください:

 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);
于 2010-03-24T19:41:12.203 に答える