计算具有相同项目计数的多个IEnumerable的平均值

时间:2018-10-17 00:34:51

标签: c# linq average ienumerable

假设我们有多个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 }

可枚举的数量可能有所不同(即不固定为四个)。

每个可枚举项的数量可能有所不同(即不固定为三个),但对于该特定实例的所有可枚举项,其数量都是相同的。

2 个答案:

答案 0 :(得分:4)

更新以响应编辑

如果您有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从每个分组中选择平均值。

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

答案 1 :(得分:2)

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