子串比较器相交

时间:2018-10-11 23:16:38

标签: c# linq substring intersect iequalitycomparer

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

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;

但是也是空的。

3 个答案:

答案 0 :(得分:3)

您正在做两个列表之间的交集,这将为您提供它们之间的通用项。由于这两个列表都没有包含相同的项目,因此您没有任何结果。

如果您要从lst获取包含num项的所有项,则可以执行以下代码,该代码使用they added an optimization to avoid the creation of bound methods方法来过滤来自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),则上面的第一个代码段是编写以下内容的简便方法:

var fin = new List<string>();

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

答案 1 :(得分:1)

确定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中的输出。

答案 2 :(得分:0)

相交从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