如何在LINQ中执行2次检查

时间:2009-12-04 19:10:54

标签: c# linq c#-3.0

public List<SavedOption> GetValidSavedOptions(
    List<Option> itemOptions, 
    List<SavedOption> savedOptions)
{
    List<SavedOption> finalSavedOptions = savedOptions.Where(x => 
        OptionTextDoesMatch(y, x) && 
        itemOptions.Any(y => y.SomeID == x.SomeID)
    ).ToList(); 
}

我对LINQ和Lambdas完全不熟悉。

在上文中,只有在列表中找到对SavedOption的{​​{1}}和OptionTextDoesMatch的调用时,我才需要/想要执行的操作包括SomeID savedOption中的SomeID。如果对itemOptions的调用返回OptionTextDoesMatch并且在true集合中找到了当前savedOptions SavedOption.SomeID,那么它将在itemOption < / p>

更新:

我试过这个,但语法仍然不适合我:

savedOptions.Where(itemOptions.Any(OptionTextDoesMatch(x,y)&amp;&amp;(y =&gt; y.SomeID == x.SomeID)))。ToList();

现在我不知道我是否可以像这样投入x。我假设如果我这样做将代表currrent savedOption并且我不需要=&gt; ?

3 个答案:

答案 0 :(得分:6)

虽然上面的答案正确,但它们是“给人一条鱼”的答案。最好借此机会学习如何将问题分解成小块,然后将结果重新组合成查询。

  

在上面,我需要/想要做什么   只有在包含SavedOption时才包括   调用OptionTextDoesMatch和SomeID   在...中找到savedOption的   itemOptions中的SomeID列表。

让我试着改写一个令人困惑的句子。

您有SavedOptions列表。每个SavedOption都有一个ID和一些文本。

您有一个选项列表。每个选项都有一个ID和一些文本。

您希望过滤SavedOptions列表,以获取与BOTH文本和ID上的某些选项匹配的SavedOptions。

打破问题。假设您没有SavedOptions序列。假设您只有一个SavedOption和一个Options列表。你怎么知道它是否匹配?

这很简单:

SavedOption mySavedOption = whatever;
bool matchExists = itemOptions.Any(item=>
    OptionTextDoesMatch(item, mySavedOption) && 
    item.SomeID == mySavedOption.SomeID);

这有意义吗?

现在假设您想要使用SavedOption创建一个谓词。你会怎么做?这很简单:

Func<SavedOption, bool> predicate = savedOption => 
    itemOptions.Any(item=>
        OptionTextDoesMatch(item, savedOption ) && 
        item.SomeID == savedOption.SomeID);

这是谓词,用于确定单个项是否匹配。

还有意义吗?如果有些事情让人感到困惑,请阻止我。

因此,要从中删除过滤器,将谓词应用于已保存选项列表中的每个项目

result = savedOptions.Where(savedOption => 
    itemOptions.Any(item=>
        OptionTextDoesMatch(item, savedOption) && 
        item.SomeID == savedOption.SomeID));

或者,在查询理解表单中,我个人觉得更容易阅读。

result = from savedOption in savedOptions
         where itemOptions.Any(item =>
             OptionTextDoesMatch(item, savedOption) && 
             item.SomeID == savedOption.SomeID)
         select savedOption;

但可能更好的选择是使用连接。 连接只是对两个与ID相关的集合的笛卡尔积的过滤器进行优化。

result = from savedOption in savedOptions
         join itemOption in itemOptions 
         on savedOption.SomeID equals itemOption.SomeID
         where OptionTextDoesMatch(itemOption, savedOption)
         select savedOption;

这是清楚的吗?

答案 1 :(得分:3)

随机猜测:

List<SavedOption> finalSavedOptions = savedOptions.Where(x => 
    itemOptions.Any(y => OptionTextDoesMatch(y, x) && y.SomeID == x.SomeID)
).ToList(); 

答案 2 :(得分:1)

在你的Where子句中,你在savedOptions方法中迭代每个对象 - 就像你做的那样:

foreach(SavedOption x in savedOptions)
{
    if (OptionTextDoesMatch(y, x)) //y is not yet specified...
    {
        foreach(Option y in itemOptions)
        {
            if (y.SomeID == x.SomeID)
                yield return x;
        }
    }
}

在您的语句中,where子句迭代您的savedOptions列表,并且每次迭代都会将savedOption的当前实例分配给'x'。然后,您正在检查'x的文本是否与您尚未指定的内容相匹配 - 'y'。

然后你进行第二次迭代:itemOptions.Any(y => y.SomeID == x.SomeID)。在这里,您已经指定y现在被定义为Option的实例,其方式与使用外部lambda表达式的方式非常相似:

foreach(Option y in itemOptions)
{
    return y.SomeID == x.SomeID;
}

因为外部子句指定了x,所以我们可以在内部子句中访问它,但事实并非如此。在内部子句之前未指定y,因此您的where子句不起作用。

为了全面诊断你想要做什么,我需要了解Option和SavedOptions对象的样子,并弄清楚你在逻辑上想要做什么才能准确解释你的lambda应该看起来......

我怀疑你真正想做的事情是:

foreach(SavedOption x in savedOptions)
    foreach(Option y in itemOptions)
        if (OptionTextDoesMatch(y, x) && (y.SomeID == x.SomeID))
            yield return x;

lambda表示法将是:

return savedOptions.Where(x => itemOptions.Any(y => OptionTextDoesMatch(y, x) && (y.SomeID == x.SomeID)));