linq除了和自定义IEqualityComparer

时间:2010-03-23 15:11:56

标签: c# iequalitycomparer

我正在尝试在两个字符串列表上实现自定义比较器,并使用.Except()linq方法来获取那些不是列表中的一个。我做自定义比较器的原因是因为我需要进行“模糊”比较,即一个列表中的一个字符串可以嵌入到另一个列表中的字符串中。

我做了以下比较器

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()永远不会被触及。有什么想法吗?

3 个答案:

答案 0 :(得分:18)

如果返回的所有哈希码都不同,则永远不需要比较相等。

基本上问题是你的哈希和相等概念是非常不同的。我不完全确定你是如何纠正这一点的,但是在你这样做之前它肯定不会起作用。

如果Equals(a, b)返回true,则需要确保GetHashCode(a) == GetHashCode(b)。 (反过来不一定是真的 - 哈希冲突是可以接受的,尽管显然你希望尽可能少地使用哈希冲突。)

答案 1 :(得分:5)

正如Jon指出的那样,你需要确保两个相等的字符串的哈希码(根据你的比较规则)。这是非常不幸的。

为了演示此问题,Equals(str, "")对所有字符串str都返回true,这实质上意味着所有字符串都等于空字符串,因此所有字符串必须具有相同的哈希码作为一个空字符串。因此,正确实现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实现的效率如何,我不确定实际上是否可以为比较规则提供任何有效的实现。

答案 2 :(得分: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);