计算具有相同项目数的多个 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())(但根据您的评论,我认为情况并非如此)。

  1. 使用 .SelectMany 将列表展平为包含项目及其子数组索引的对象(因此 10 和 11 将有 Index 0,等等)。
  2. 按索引分组。
  3. 使用 .Select 到 select 每个分组的平均值。

Try it online

Try it online with question data

原回答

您可以使用 .Zip 合并两个列表并计算平均值:

var averages = items1
                  .Zip(items2, (a, b) => (a+b)/2.0)
                  .ToArray();

Try it online

由于您对压缩两个以上的 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()