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.Name
的Arrangements
,并获得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
我已经尝试使用Distinct
和Aggregate
,它只是没有得到我任何地方。我总是拿不到这样或那样的列表。有人能帮忙吗?
下面是我当前聚合的一个例子。
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
无关。我必须对两个不同的数组执行相同的操作,但它们彼此之间没有任何共同之处。学习如何与一个人相处,会让我知道如何与另一个人相处。
如果步骤和光圈之间没有相关性,则可以这样做:
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() };
}
这里缺少了什么?您还想如何"聚合"这些安排和步骤?(编辑:看了你的评论后,也许这实际上是你想要的。)