3

我有一个IEnumerable<IEnumerable<CustomObject>>s 其中CustomObject有一个x(用作键(在本例1中为 , 2, 3))和一个y值。一些假数据:

{
  { {1, 2}, {2, 4}, {3, 6}, {4, 8} }, 
  { {1, 2}, {2, 0}, {3, 0}, {4,-2} },
  { {1, 2}, {2, 2}, {3, 0}, {4, 0} }
}

我可以检索以下内容的最佳方法是什么IEnumerable<CustomObject>

{ {1, 2}, {2, 2}, {3, 2}, {4, 2} }

y每个元素的平均值。

性能需要合理,所以不能.ToList()使用或类似。我一直在尝试使用 LINQ 进行各种尝试,但无济于事。

更新

@Bort,@Rawling,我已经测试了你的答案,@Rawling 的答案要快得多。但是,@Bort 的答案更具可读性,所以我想我现在会继续这样做。请随时保持答案!

4

4 回答 4

5

SelectMany使用 LINQ,您可以使用、GroupByx 和Select平均值来展平列表列表:

var averages = customObjectLists
    .SelectMany(l => l)
    .GroupBy(co => co.x)
    .Select(g => new CustomObject { x => g.Key, y = g.Average(co => co.y) });
于 2012-08-09T13:19:58.967 回答
1

像这样的东西应该会给你你正在寻找的结果。它将列表列表扁平化为单个List<CustomObject>,然后按值分组并对X值进行平均Y,从而为您留下具有和属性IEnumerable的匿名类型。您可以更改为 调用构造函数,您将得到一个.XYselect new {} ...CustomObjectIEnumerable<CustomObject>

var myComplexObject = //your IEnumerable<IEnumerable<CustomObject>>
var result = from firstList in myComplexObject
        from secondList in firstList
        group secondList by secondList.X into grp
        select new {X = grp.Key, Y = (int)grp.Average(p=>p.Y)};
于 2012-08-09T13:17:16.240 回答
1

如果您不介意固化外部枚举器,以下 LINQy 方法将推迟内部枚举器的执行。

IEnumerable<V> AggregateAcross<T, U, V>(
            IEnumerable<IEnumerable<T>> input,
            Func<T, U> select,
            Func<IEnumerable<U>, V> aggregate)
    {
        var enumerators = input.Select(ie => ie.GetEnumerator()).ToArray();
        while (enumerators.All(e => e.MoveNext()))
        {
            yield return aggregate(enumerators.Select(e => select(e.Current)));
        }
    }

调用例如

foreach (var avg in AggregateAcross(
                     input,
                     pair => pair.y,
                     e => e.Average(y => y)))
{
    Console.WriteLine(avg);
}

请注意,一旦内部枚举器之一用完元素,这就会停止。此外,当你完成后,它需要一些东西来处理所有的枚举器。看看这个答案以获得更多的想法。

(另请注意,这完全忽略了这些x值。由于您的所有输入都是有序的,并且您想要的输出也是有序的,因此这些x值不会添加任何内容。)

于 2012-08-09T13:35:31.420 回答
-1

我没有测试它,但我认为这应该工作。

public void Test() {
    IEnumerable<IEnumerable<CustomObject>> data = ...;
    var result = data
        .SelectMany(x => x)
        .GroupBy(
            item => item.x,
            (key, r) => new { x = key, data = r.Select(z => z.y) }
        )
        .Select(x => new CustomObject { x = x.x, y = (int)x.data.Average() })
        .ToList();
}
于 2012-08-09T13:14:05.423 回答