将 LINQ 与 WHERE 结合使用,无需冗余"||"命令即可请求多个可能的结果



这是一个化妆问题,它只是语法糖,只是因为我想这样做。但基本上我有很多这样的代码…我使用dynamic纯粹是为了节省时间和举例。

var terms = new List<string> {"alpha", "beta", "gamma", "delta", "epsilon", "rho"};
var list = new List<dynamic> {
    new {
        Foo = new List<string> {
            "alpha",
            "gamma"
        }
    }
};
var result = list
     .Where(
          n => n.Foo.Contains(terms[0]) ||
               n.Foo.Contains(terms[1]) ||
               n.Foo.Contains(terms[2]) ||
               n.Foo.Contains(terms[3]) ||
               n.Foo.Contains(terms[4]) ||
               n.Foo.Contains(terms[5]))
     .ToList();

显然这是一个可笑的夸张的例子,更准确的代码是…

    Baseline =
        Math.Round(Mutations.Where(n => n.Format.Is("Numeric"))
            .Where(n => n.Sources.Contains("baseline") || n.Sources.Contains("items"))
            .Sum(n => n.Measurement), 3);

但基本的一点是,我有很多地方,我想检查,看看如果一个List<T>(通常是List<string>,但有时可能有其他对象。string是我目前的重点)包含来自另一个List<T>的任何项目。

我认为使用.Any()会起作用,但我实际上还没有能够像预期的那样发挥作用。到目前为止,只有过量的"||"才能产生正确的结果。

这在功能上很好,但是写起来很烦人。我想知道是否有一种更简单的方法来写这个——一个扩展方法,或者一个LINQ方法,也许我还没有理解。

<标题> 更新

我真的知道这个可能是重复的,但是我很难把问题的措辞精确到我可以找到重复的程度。如有任何帮助,不胜感激。

<标题> 解决方案非常感谢你所有的帮助。这是完整的解。我在这里使用dynamic只是为了节省示例类的时间,但是您提出的几个解决方案都有效。
var terms = new List<string> {"alpha", "beta", "gamma", "delta", "epsilon", "rho"};
var list = new List<dynamic> {
    new  { // should match
        Foo = new List<string> {
            "alpha",
            "gamma"
        },
        Index = 0
    },
    new { // should match
        Foo = new List<string> {
            "zeta",
            "beta"
        },
        Index = 1
    },
    new { // should not match
        Foo = new List<string> {
            "omega",
            "psi"
        },
        Index = 2
    },
    new  { // should match
        Foo = new List<string> {
            "kappa",
            "epsilon"
        },
        Index = 3
    },
    new  { // should not match
        Foo = new List<string> {
            "sigma"
        },
        Index = 4
    }
};
var results = list.Where(n => terms.Any(t => n.Foo.Contains(t))).ToList();
// expected output - [0][1][3]
results.ForEach(result => {
    Console.WriteLine(result.Index);
});

我认为使用.Any()会起作用,但我实际上还没有能够像预期的那样发挥作用。

您应该能够通过将Any()应用于terms来使其工作,如下所示:

var result = list
         .Where(n => terms.Any(t => n.Foo.Contains(t)))
         .ToList();

你可以试试这个:

var result = list.Where(terms.Contains(n.Foo))
                 .ToList();

我假设n.Foo是一个字符串而不是一个集合,在这种情况下:

var terms = new List<string> { "alpha", "beta", "gamma", "delta", "epsilon", "rho" };
var list = (new List<string> { "alphabet", "rhododendron" })
    .Select(x => new { Foo = x });
var result = list.Where(x => terms.Any(y => x.Foo.Contains(y)));

您想知道一个集合中的Any元素是否存在于另一个集合中,因此Intersect在这里应该可以很好地工作。

你可以相应地修改你的第二个代码片段:

var sources = new List<string> { "baseline", "items" };
Baseline =
    Math.Round(Mutations.Where(n => n.Format.Is("Numeric"))
        .Where(n => sources.Intersect(n.Sources).Any())
        .Sum(n => n.Measurement), 3);

关于你为"机密数据库"引用的部分文档:

使用默认的相等比较器比较值,产生两个序列的集合交集。

每个对象都可以与相同类型的对象进行比较,以确定它们是否相等。如果它是你创建的自定义类,你可以实现IEqualityComparer,然后你可以决定什么使你的类的两个实例"相等"。

然而,在这种情况下,我们只是比较字符串,没有什么特别的。"Foo" = "Foo",但"Foo"≠"Bar" 因此,在上面的代码片段中,我们通过比较第一个集合中的所有字符串与第二个集合中的所有字符串来交叉两个集合。在两个集合中"相等"的字符串将在第三个集合中结束。

然后调用"Any()"来确定第三个集合中是否有元素,这告诉我们两个原始集合之间至少有一个匹配

如果使用Any()时性能是一个问题,您可以使用正则表达式代替。显然,您应该度量以确保正则表达式执行得更快:

var terms = new List<string> { "alpha", "beta", "gamma", "delta", "epsilon", "rho" };
var regex = new Regex(string.Join("|", terms));
var result = list
             .Where(n => regex.Match(n.Foo).Success);

这假设将术语连接到一个列表中创建一个有效的正则表达式,但是使用简单的单词应该没有问题。

使用正则表达式的一个优点是,您可以要求术语被单词边界包围。此外,与在Any中使用Contains的解决方案相比,Where子句中的谓词可能更容易理解。

最新更新