【问题标题】:LINQ Intersect on inner collection内部集合上的 LINQ 相交
【发布时间】:2016-03-04 10:07:23
【问题描述】:

我有一个 Stores 列表(ObservableCollection<Store> 类型),Store 对象有一个名为 Features 的属性(List<Feature> 类型)。并且Feature 对象有一个Name 属性(string 类型)。

回顾一下,包含功能列表的商店列表

我有第二个 DesiredFeatures 集合(List<string> 类型)。

我需要使用 LINQ 为我提供具有所有 DesiredFeatures 的商店的结果。到目前为止,我只能想出一个查询,它给我一个 OR 结果而不是 AND

看起来是这样的:

var q = Stores.Where(s=> s.Features.Any(f=> DesiredFeatures.Contains(f.name)));

我知道Intersect 可以提供帮助,以下是我的使用方法:

var q = Stores.Where(s => s.Features.Intersect<Feature>(DesiredFeatures));

这是我卡住的地方,Intersect 想要一个 Feature 对象,我需要相交的是 Feature.Name。

我们的目标是最终得到一个 ObservableCollection,其中每个 Store 都有所有 DesiredFeatures。

谢谢!

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    您几乎已经完成了您需要的工作。一个小的改进是交换 DesiredFeaturess.Features

    var q = Stores.Where(s => DesiredFeatures.All(df => s.Features.Contains(df)));
    

    这意味着只取那些所需特征都包含在商店特征中的商店。

    【讨论】:

    • 非常接近,但我的df 是一个字符串,而不是一个功能。我想我可以重构使 DesiredFeatures 成为 List,但这似乎是一种创可贴
    【解决方案2】:

    我需要使用 LINQ 只为我提供具有所有 DesiredFeatures 的商店的结果。

    换句话说,每个所需的功能都必须具有匹配的商店功能。

    我看不出Intersect 在这种情况下有什么帮助。上述标准直接翻译成LINQ是这样的:

    var q = Stores.Where(s =>
        DesiredFeatures.All(df => s.Features.Any(f => f.Name == df))
    );
    

    更有效的方法是使用GroupJoin 进行匹配:

    var q = Stores.Where(s => 
        DesiredFeatures.GroupJoin(s.Features,
            df => df, sf => sf.Name, (df, sf) => sf.Any()
        ).All(match => match)
    );
    

    Except 检查不匹配的项目:

    var q = Stores.Where(s =>
        !DesiredFeatures.Except(s.Features.Select(sf => sf.Name)).Any()
    );
    

    【讨论】:

    • 感谢 Ivan,GroupJoin 是完美的解决方案并且成功了。
    【解决方案3】:

    继续您的相交想法,我想到的唯一方法是使用Select 获取 Store.Features (List<Feature>) 作为功能名称列表 (List<string>) 并将其与所需功能。

    更新答案:

    var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures).Any());
    

    var q = Stores.Where(s => DesiredFeatures.Intersect(s.Features.Select(f => f.Name)).Any());
    

    旧答案(如果 DesiredFeatures 是 List<Feature>

    var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures.Select(df => df.Name)).Any());
    

    【讨论】:

    • 也非常接近,但 DesiredFeatures 是 List<string>。如果我更改 DesiredFeatures.Select(df=>df) 我会得到与我最初尝试相同的结果。
    • 哦,抱歉。我没有看到 DesiredFeatures 是一个字符串列表。它是功能名称列表还是其他信息?您可能也应该在问题中指定这一点。
    • 是的,我知道它在我的第一个查询中是这样显示的,但是谓词中的 f.name 来自 Features。我正在尝试重构为 List ,因为它可能不那么复杂
    • 我已经更新了我的答案。值得注意的一件事是,您需要在 Store.Features 上调用 Select,以便与 List(功能名称列表)相交。
    【解决方案4】:

    您希望代码执行的两件事。

    var q = Stores.Where(s=> s.Features.All(f=> DesiredFeatures.Contains(f.name)) && 
                             s.Features.Count() == DesiredFeatures.Count()); // Incude Distinct in the comparison if Features list is not unique
    
    • 确保每个功能都是 DesiredFeature
    • 商店包含所有所需的功能。

    上面的代码假定Features 集合以及DesiredFeatures 中的唯一性,如果这不正确,请按照注释行中的说明修改代码

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-31
      相关资源
      最近更新 更多