LINQ聚合与子聚合

本文关键字:LINQ | 更新日期: 2023-09-27 17:53:05

使用半复杂的结构,我试图使用Linq Aggregate方法将几个对象"组合"成一个(尽管如果有更好的方法,我愿意接受想法)。

这是我的基本类设计。

class Aspect {
  string Name { get; set; }
}
class Arrangement {
  Aspect Aspect { get; set; }
  IList<Aperture> Apertures { get; set; }
  IList<Step> Steps { get; set; }
}
class Step {
  int Rank { get; set; }
  int Required { get; set; }
}
class Aperture {
  string Name { get; set; }
  int Size { get; set; }
}

基本上,我试图聚合IEnumerable<Arrangement>的整个层次结构,并将所有内容保持在基本级别,但是在可以适当覆盖的地方,我想覆盖它们。

更新

我想获得所有共享相同Aspect.NameArrangements,并获得Steps的完整列表,覆盖较低级别的步骤,其中较高级别的安排具有相同的秩和不同的Required值。

例如…

var list = new List<Arrangement>{
    new Arrangement{
      Aspect = Aspects.Named("One"),
      Steps = new List<Step>{
            new Step {
               Rank = 1,
               Required = 2
            },
            new Step {
               Rank = 2,
               Required = 4
            }
        }
    },
    new Arrangement{
      Aspect = Aspects.Named("One"),
      Steps = new List<Step>{
            new Step {
               Rank = 1,
               Required = 3
            }
        }
    }
  }

当聚合正确时,它应该看起来像…

Arrangement
 - Aspect
    - Name : One
 - Steps 
    - Rank : 1
    - Required : 3
    - Rank : 2
    - Required : 4

我已经尝试使用DistinctAggregate,它只是没有得到我任何地方。我总是拿不到这样或那样的列表。有人能帮忙吗?

更新

下面是我当前聚合的一个例子。

public static Layouts.Template Aggregate(this IList<Layouts.Template> source) {
            return source.Aggregate(
                source.First(),
                (current, next) => new Layouts.Template {
                    Apertures = (current.Apertures.Concat(next.Apertures).Distinct().ToList()),
                    Arrangements = (current.Arrangements.Concat(next.Arrangements).Distinct().ToList()),
                    Pages = (current.Pages.Concat(next.Pages).Distinct().ToList())
    });
        }

我的问题是,我有很多麻烦,在我的头脑中如何做到这一点,更不用说在一个表达式。我并不是不愿意使用多个方法,但是如果我能将它们全部封装起来,那将非常有用。总的来说,我对LINQ很着迷,我真的很想了解这个。

更新2

另一个集合Apertures将以类似的方式工作,但它与Steps无关。我必须对两个不同的数组执行相同的操作,但它们彼此之间没有任何共同之处。学习如何与一个人相处,会让我知道如何与另一个人相处。

LINQ聚合与子聚合

如果步骤和光圈之间没有相关性,则可以这样做:

var result = new Arrangement{
    Steps = list.SelectMany(arrangement => arrangment.Steps)
                .GroupBy(step => step.Rank)
                .Select(l => l.Last())
                .OrderBy(step => step.Rank)
                .ToList()),
}

如果有,你需要以某种方式将两者结合起来。如果步骤索引到光圈,那么你可以使用类似的东西。

更新后:

var query = arrangements
    .GroupBy(a => a.Aspect.Name)
    .Select(g => 
    new Arrangement
    { 
        Steps = ga.SelectMany(a => a.Steps)
                  .GroupBy(s => s.Rank)
                  .Select(gs => gs.Last()),
        Aspect = ga.First().Aspect
    });

这将创建与示例中相同的输出。

现在,如何将它与当前的聚合方法合并?根据我的理解,您想要从所有当前布局内容(包括安排,页面等)创建一个大布局?

您根本不需要聚合,只需将其拆分为3个LINQ查询:

// get all arrangements object from all layouts [flattening with SelectMany]
var arrangements = source.SelectMany(s => s.Arrangements);
// and filter them
var filteredArrangements = // enter larger query from above here         
// repeat the same for Apertures and Pages
... 
// and return single object
return new Layouts.Template 
       {
           Apertures = filteredApertures,
           Arrangements = filteredArrangements,
           Pages = filteredPages
       };

我认为这个不是您想要的完整解决方案:

private static Arrangement Accumulate(IEnumerable<Arrangement> arrangements)
{
    var stepsByRank = new Dictionary<int, Step>();
    foreach (var arrn in arrangements)
        foreach (var step in arrn.Steps)
            stepsByRank[step.Rank] = step;
    return new Arrangement { Steps = stepsByRank.Values.ToArray() };
}

这里缺少了什么?您还想如何"聚合"这些安排和步骤?(编辑:看了你的评论后,也许这实际上是你想要的。)