LINQ与子聚合聚合

时间:2011-04-25 19:17:56

标签: c# linq

使用半复杂的结构,我试图使用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>的整个层次结构并将所有内容保留在基础级别,但是在可以适当覆盖的地方,我想覆盖它们。

更新

  

我想让所有Arrangements共享相同的Aspect.Name,并获得Steps的完整列表,覆盖较低级别的排名,其中较高级别的排列具有相同的排名而不同所需的价值。

举个例子......

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无关。只需要两个不同的阵列,我必须做同样的事情,但它们之间没有任何共同之处。学习如何用一个人来做这件事会让我知道如何与另一个人一起做。

3 个答案:

答案 0 :(得分:2)

如果步骤和光圈之间没有关联,你可以这样做:

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

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

答案 1 :(得分:1)

更新后:

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
       };

答案 2 :(得分:1)

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

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() };
}

这有什么缺失?你还想怎样“聚合”这些安排和步骤? (编辑:阅读你的评论后,也许这实际上就是你想要的。)