我有一个IEnumerable<IEnumerable<CustomObject>>
,其中CustomObject
有一个x
(用作密钥(在本例中为1
,2
,{{ 1}}))和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
或类似的。我一直在用LINQ尝试各种各样的东西,但无济于事。
答案 0 :(得分:5)
使用LINQ,您可以使用SelectMany
,然后GroupBy
x和Select
平均列出列表列表:
var averages = customObjectLists
.SelectMany(l => l)
.GroupBy(co => co.x)
.Select(g => new CustomObject { x => g.Key, y = g.Average(co => co.y) });
答案 1 :(得分:1)
这样的事情可以让你得到你正在寻找的结果。它会将列表列表展平为一个List<CustomObject>
,然后按X
值进行分组并平均Y
值,为您留下IEnumerable
的匿名输入X
和Y
属性。您可以更改select new {} ...
以调用CustomObject
的构造函数,然后您将获得IEnumerable<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)};
答案 2 :(得分: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);
}
请注意,只要其中一个内部枚举器耗尽了元素,就会停止此操作。此外,当你完成后,它需要一些东西来处理所有的枚举器。请查看this answer以获取更多想法。
(另请注意,这完全忽略了x
值。由于所有输入都是有序的,并且您所需的输出也是有序的,x
值不会添加任何内容。)
答案 3 :(得分:-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();
}