【问题标题】:Substring comparer on Intersect相交上的子字符串比较器
【发布时间】:2019-03-17 03:05:13
【问题描述】:

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

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;

但也是空的。

【问题讨论】:

  • X、Y、Z 是字符串而不是字符,可以是:XXX、Y、ZZZZZ
  • 你的相等比较器一开始就坏了。您似乎正在尝试使用它来使“abcXdef”等于“X”,但您有很多问题。例如,首先,您的 equals 是不可逆的。所以Equals(x,y) 不会给出与Equals(y,x) 相同的结果。您的 getHashCode 也是错误的,这可能是什么都没发生的原因。 “abcXdef”与“X”有不同的哈希码,所以它们不可能相同,所以它甚至可能没有运行你的 Equals 方法......
  • 感谢您的评论,我已尝试 GetHashCode 全部返回 1,一些字符串在列表中但并非全部都应在列表中,我想 Linq 内部有一些优化,并非所有元素都检查 Equals功能。
  • 我评论的重点不仅在于指出您的平等实施中的缺陷,而且还质疑它是否是正确的做事方式。 “x”和“abcXdef”在任何实际意义上都不相等,因此制作一个说它们相等的比较器是愚蠢的。假设对于相等比较器,如果 a=b 和 b=c 则 a =c 应该是正确的,如果一个字符串是另一个字符串的子字符串,则两个字符串相等,您最终将不得不证明所有字符串都等于每个字符串其他或多或少。
  • 你说得对@Chris,谢谢!现在,我明白了。

标签: c# linq substring intersect iequalitycomparer


【解决方案1】:

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

如果您想从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),上面的第一个代码 sn-p 是编写以下内容的简写方式:

var fin = new List<string>();

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

【讨论】:

  • 非常感谢,我是 Linq 问题的新手,使用 foreach 对我来说很容易做到,但我想学习/理解 Linq。
【解决方案2】:

当然,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中的输出。

【讨论】:

  • 非常感谢您的解释,我现在明白了。不知道dotnetfiddle.net很有用,谢谢!
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    • 2022-10-15
    • 2010-10-19
    • 2020-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多