计算具有相同项目数的多个 IEnumerable 的平均值
Calculate averages of multiple IEnumerable with same item count
假设我们有多个 IEnumerable
相同的项目数
var multipleEnumerables = new[]
{
new[] { 10, 20, 30 }
new[] { 11, 21, 31 }
new[] { 12, 22, 32 }
new[] { 13, 23, 33 }
}
我怎样才能得到那些使用 LINQ 的平均值,这将产生以下结果:
new[] { 11.5, 21.5, 31.5 }
可枚举数的数量可能会有所不同(即不固定为四个)。
每个可枚举项中的项数可能会有所不同(即不固定为三个),但对于该特定实例的所有可枚举项都是相同的。
更新响应编辑
如果你有 IEnumerable<IEnumerable<Item>>
你可以使用这样的东西:
IEnumerable<IEnumerable<Test>> multipleEnumerables = new[] {
new [] { new Test { Value = 10 }, new Test { Value = 20 } },
new [] { new Test { Value = 11 }, new Test { Value = 21 } }
};
var averages = multipleEnumerables
.SelectMany(e => e.Select((v, i) => new { Index = i, Item = v }))
.GroupBy(e => e.Index)
.Select(e => e.Select(v => v.Item.Value).Average())
.ToArray();
如果您有一个简单的 IEnumerable<IEnumerable<int>>
,请将 .Select
行更改为:.Select(e => e.Select(v => v.Item).Average())
(但根据您的评论,我认为情况并非如此)。
- 使用
.SelectMany
将列表展平为包含项目及其子数组索引的对象(因此 10 和 11 将有 Index
0,等等)。
- 按索引分组。
- 使用
.Select
到 select 每个分组的平均值。
Try it online with question data
原回答
您可以使用 .Zip
合并两个列表并计算平均值:
var averages = items1
.Zip(items2, (a, b) => (a+b)/2.0)
.ToArray();
由于您对压缩两个以上的 IEnumerable<T>
很感兴趣,这里有一个扩展方法 (ZipAll
),展示了如何将多个 IEnumerable<T>
压缩在一起。实际上,这会旋转数据,使列变成行。
public static class ZipEx
{
public static IEnumerable<IEnumerable<T>> ZipAll<T>(
this IEnumerable<IEnumerable<T>> src)
{
return src
.Aggregate(
(IEnumerable<IEnumerable<T>>)null,
(acc, curr) => acc == null
? curr.Select(x => x.ToEnumerable())
: acc.Zip(curr, (a, c) => a.Append(c)));
}
public static IEnumerable<T> ToEnumerable<T>(this T item)
{
yield return item;
}
}
使用这种 ZipAll
方法,现在可以轻松地:
var averages = multipleEnumerables.ZipAll().Select(x => x.Average()); //.ToArray()
假设我们有多个 IEnumerable
相同的项目数
var multipleEnumerables = new[]
{
new[] { 10, 20, 30 }
new[] { 11, 21, 31 }
new[] { 12, 22, 32 }
new[] { 13, 23, 33 }
}
我怎样才能得到那些使用 LINQ 的平均值,这将产生以下结果:
new[] { 11.5, 21.5, 31.5 }
可枚举数的数量可能会有所不同(即不固定为四个)。
每个可枚举项中的项数可能会有所不同(即不固定为三个),但对于该特定实例的所有可枚举项都是相同的。
更新响应编辑
如果你有 IEnumerable<IEnumerable<Item>>
你可以使用这样的东西:
IEnumerable<IEnumerable<Test>> multipleEnumerables = new[] {
new [] { new Test { Value = 10 }, new Test { Value = 20 } },
new [] { new Test { Value = 11 }, new Test { Value = 21 } }
};
var averages = multipleEnumerables
.SelectMany(e => e.Select((v, i) => new { Index = i, Item = v }))
.GroupBy(e => e.Index)
.Select(e => e.Select(v => v.Item.Value).Average())
.ToArray();
如果您有一个简单的 IEnumerable<IEnumerable<int>>
,请将 .Select
行更改为:.Select(e => e.Select(v => v.Item).Average())
(但根据您的评论,我认为情况并非如此)。
- 使用
.SelectMany
将列表展平为包含项目及其子数组索引的对象(因此 10 和 11 将有Index
0,等等)。 - 按索引分组。
- 使用
.Select
到 select 每个分组的平均值。
Try it online with question data
原回答
您可以使用 .Zip
合并两个列表并计算平均值:
var averages = items1
.Zip(items2, (a, b) => (a+b)/2.0)
.ToArray();
由于您对压缩两个以上的 IEnumerable<T>
很感兴趣,这里有一个扩展方法 (ZipAll
),展示了如何将多个 IEnumerable<T>
压缩在一起。实际上,这会旋转数据,使列变成行。
public static class ZipEx
{
public static IEnumerable<IEnumerable<T>> ZipAll<T>(
this IEnumerable<IEnumerable<T>> src)
{
return src
.Aggregate(
(IEnumerable<IEnumerable<T>>)null,
(acc, curr) => acc == null
? curr.Select(x => x.ToEnumerable())
: acc.Zip(curr, (a, c) => a.Append(c)));
}
public static IEnumerable<T> ToEnumerable<T>(this T item)
{
yield return item;
}
}
使用这种 ZipAll
方法,现在可以轻松地:
var averages = multipleEnumerables.ZipAll().Select(x => x.Average()); //.ToArray()