如何避免两次迭代此集合?

时间:2014-06-13 15:14:39

标签: c# .net linq

注意:由于机密性,我已更改了收藏品的名称。

请考虑以下代码:

o.Flag =
    o2.Collection1
        .Any(cpd => cpd.Collection1
            .Any(plc => plc.Collection1
                .Any(vd => vd.DetailedFlag))) ||
    o2.Collection1
        .Any(cpd => cpd.Collection2
            .Any(plc => plc.Collection1
                .Any(vd => vd.DetailedFlag)));

显然我正在做的是将详细的标志扁平化为整体标志,但这段代码将迭代o2.Collection1两次。

我不知道SelectMany如何能够完成这项工作,因为这些标志位于两个不同的集合上(即我没有展开集合的集合)。

我怎样才能避免这样做?

注意:我觉得Jon Skeet,当我看到这篇文章(Using LINQ to flatten a hierarchical dataset - with a caveat)基本上是说我被卡住了。但希望我读错了!

2 个答案:

答案 0 :(得分:6)

如果集合属于同一类型(或者具有定义足够信息的公共基本类型),您可以在查询中简单地连接它们:

o.Flag =
    o2.Collection1
        .Any(cpd => cpd.Collection1.Concat(cpd.Collection2)
            .Any(plc => plc.Collection1
                .Any(vd => vd.DetailedFlag)));

请注意,这里的主要优点是简单地进行查询,并减少代码重复。它对其执行效果不会产生任何明显影响as long as your collection is actually an in memory collection

如果它们不是兼容类型(或者每个子集合的谓词存在细微差别,与给出的示例不同),那么您可以管理的最好的是将两个子查询都拉入到谓词中。主要收藏:

o.Flag =
    o2.Collection1
        .Any(cpd => cpd.Collection1
            .Any(plc => plc.Collection1
                .Any(vd => vd.DetailedFlag)) ||
            cpd.Collection2
            .Any(plc => plc.Collection1
                .Any(vd => vd.DetailedFlag)));

答案 1 :(得分:4)

您可以使用单次迭代直到第一层,然后分支到两个单独的查询。

o.Flag =
    o2.Collection1
        .Any(cpd => cpd.Collection1
            .Any(plc => plc.Collection1
                .Any(vd => vd.DetailedFlag)) || 
             cpd.Collection2
            .Any(plc => plc.Collection1
                .Any(vd => vd.DetailedFlag)));