使用带有WHERE的LINQ来请求多个可能的结果而没有多余的“||”命令

时间:2014-06-17 12:55:23

标签: c# linq

这是一个化妆品问题,它只是语法糖,只是因为我想这样做。但基本上我有很多代码都是这样的......我使用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);
});

5 个答案:

答案 0 :(得分:4)

  

我认为使用.Any()会起作用,但实际上我无法按预期运行。

您应该可以通过将Any()应用于terms来使其发挥作用,如下所示:

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

答案 1 :(得分:1)

你可以尝试这个:

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

答案 2 :(得分:1)

您想知道一个集合中的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);

关于您引用的文档部分&#34; Intersect&#34;:

  

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

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

然而,在这种情况下,我们只是比较字符串,没什么特别的。 &#34;富&#34; =&#34; Foo&#34;,但&#34; Foo&#34; ≠&#34; Bar&#34;

因此,在上面的代码片段中,我们通过将第一个集合中的所有字符串与第二个集合中的所有字符串进行比较来交叉两个集合。无论哪个字符串都是&#34;相等&#34;在两个集合中最终都会产生第三个集合。

然后我们打电话给#34; Any()&#34;确定第三个集合中是否有任何元素,告诉我们两个原始集合中至少有一个匹配。

答案 3 :(得分:1)

如果使用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);

这假设将术语加入列表会创建一个有效的正则表达式,但使用简单的单词不应该是一个问题。

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

答案 4 :(得分:1)

我认为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)));