Intersect 上的子字符串比较器

Substring comparer on Intersect

我需要在字符串之间进行交集,但比较子字符串:

public class MiNumeroEqualityComparer : IEqualityComparer<string> {
    public bool Equals(string x, string y) => x.Contains(y);
    public int GetHashCode(string obj) => obj.GetHashCode();
}

List<string> lst = new List<string> { "abcXdef", "abcXdef", "abcede", "aYcde" };
List<string> num = new List<string> { "X", "Y", "Z" };

var fin = lst.Intersect(num, new MiNumeroEqualityComparer());

我希望在 fin 中:"abcXdef"、"abcXdef"、"aYcde"

但是里面是空的,为什么?

首先,我尝试了不区分大小写的子字符串:(也没有成功)

public bool Equals(string x, string y) => x.IndexOf(y, StringComparison.InvariantCultureIgnoreCase) >= 0;

但也是空的。

Intersect 从 2 个集合中获取公共元素。这里的 Intersect 方法很优雅。它可以用于多种类型的元素。

您的结果为空,因为它不是列表中的常用值。

  List<string> lst = new List<string> { "abcXdef", "abcXdef", "abcede", "aYcde" };
            List<string> num = new List<string> { "X", "Y", "abcXdef", "Z", "aYcde" };

            var fin = lst.Intersect(num);

fin >> abcXdef,aYcde

您正在对两个列表进行交集,这将为您提供它们之间的共同项目。由于两个列表都不包含相同的项目,因此您得不到任何结果。

如果你想从 lst 中获取所有包含来自 num 的项目的项目,那么你可以执行类似下面的代码,它使用 string.Contains 方法来从 lst 过滤项目:

var fin = lst.Where(item => num.Any(item.Contains));

结果:

{ "abcXdef", "abcXdef", "aYcde" }

或者,如果您确实想执行不区分大小写的查询,您可以改用 IndexOf 方法:

var fin = lst.Where(item => num.Any(n => 
    item.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0));

如果这很难理解(有时 Linq 是),上面的第一个代码片段是 shorthand 编写以下内容的方式:

var fin = new List<string>();

foreach (var item in lst)
{
    foreach (var n in num)
    {
        if (item.Contains(n))
        {
            fin.Add(item);
            break;
        }
    }
}

当然,Rufus 已经在提供的答案中解决了您的问题。但是让我解释一下为什么您的方法不起作用。

它产生空结果的原因是因为 Equals(string x, string y) 永远不会被调用。它可以从 GetHashCode 方法中推断出不等式。如果哈希值相同,那么它将调用 Equals。换句话说,你在 Equals 中的逻辑将永远不会被执行。

这是一些代码,您可以看到发生了什么。

class Program
{
    static void Main(string[] args)
    {
        // See I added an item at the end here to show when Equals is called
        List<string> lst = new List<string> { "abcXdef", "abcXdef", "abcede", "aYcde", "X" };
        List<string> num = new List<string> { "X", "Y", "Z" };

        var fin = lst.Intersect(num, new MiNumeroEqualityComparer()).ToList();
        Console.ReadLine();
    }
}

public class MiNumeroEqualityComparer : IEqualityComparer<string>
{
    public bool Equals(string x, string y)
    {
        Console.WriteLine("Equals called for {0} and {1}.", x, y);
        return x.Contains(y);
    }

    public int GetHashCode(string obj)
    {
        Console.WriteLine("GetHashCode alled for {0}.", obj);
        return obj.GetHashCode();
    }
}

如果您 运行 上面的代码,它只会为产生相同散列的项目调用 Equals;所以仅适用于 "X"。

查看 this fiddle 中的输出。