来自IEnumerable <ienumerable <t>&gt;的IEnumerable中的一个属性的平均数。其中T有两个属性</ienumerable <t>

时间:2012-08-09 12:59:09

标签: c# .net-3.5

我有一个IEnumerable<IEnumerable<CustomObject>>,其中CustomObject有一个x(用作密钥(在本例中为12,{{ 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尝试各种各样的东西,但无济于事。

更新

@Bort,@ Rawling,我已经测试了你的答案,@ Rawling的速度非常快。然而,@ Bort的答案更具可读性,所以我想我会暂时解决这个问题。请随时保持答案!

4 个答案:

答案 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的匿名输入XY属性。您可以更改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();
}