与Linq的数学统计

时间:2010-11-09 13:52:08

标签: c# linq

我有对象(IEnumerable)的集合,每个人都有年龄属性。

我想在这个年龄属性上为集合生成统计数据,例如Max,Min,Average,Median等。

使用LINQ执行此操作的最优雅方法是什么?

4 个答案:

答案 0 :(得分:33)

这是一个完整的,通用的Median实现,可以正确处理空集合和可空类型。它具有LINQ友好的Enumerable.Average风格,例如:

    double? medianAge = people.Median(p => p.Age);

当集合中没有非null值时,此实现返回null,但如果您不喜欢可为空的返回类型,则可以轻松地将其更改为抛出异常。

public static double? Median<TColl, TValue>(
    this IEnumerable<TColl> source,
    Func<TColl, TValue>     selector)
{
    return source.Select<TColl, TValue>(selector).Median();
}

public static double? Median<T>(
    this IEnumerable<T> source)
{
    if(Nullable.GetUnderlyingType(typeof(T)) != null)
        source = source.Where(x => x != null);

    int count = source.Count();
    if(count == 0)
        return null;

    source = source.OrderBy(n => n);

    int midpoint = count / 2;
    if(count % 2 == 0)
        return (Convert.ToDouble(source.ElementAt(midpoint - 1)) + Convert.ToDouble(source.ElementAt(midpoint))) / 2.0;
    else
        return Convert.ToDouble(source.ElementAt(midpoint));
}

答案 1 :(得分:27)

var max = persons.Max(p => p.age);
var min = persons.Min(p => p.age);
var average = persons.Average(p => p.age);

修复了偶数个元素的中位数

int count = persons.Count();
var orderedPersons = persons.OrderBy(p => p.age);
float median = orderedPersons.ElementAt(count/2).age + orderedPersons.ElementAt((count-1)/2).age;
median /= 2;

答案 2 :(得分:9)

Max,Min,Average是Linq的一部分:

int[] ints = new int[]{3,4,5};
Console.WriteLine(ints.Max());
Console.WriteLine(ints.Min());
Console.WriteLine(ints.Average());

中位数很容易:

<强>更新

我已添加订单:

ints.OrderBy(x=>x).Skip(ints.Count()/2).First();

<强>提防

所有这些操作都是循环完成的。例如,ints.Count()是一个循环,所以如果你已经获得了ints.Length并存储到一个变量或者只是按原样使用它,那就更好了。

答案 3 :(得分:1)

使用Linq获取中位数(适用于偶数或奇数个元素)

int count = persons.Count();

if (count % 2 == 0)
    var median = persons.Select(x => x.Age).OrderBy(x => x).Skip((count / 2) - 1).Take(2).Average();
else
    var median = persons.Select(x => x.Age).OrderBy(x => x).ElementAt(count / 2);