与Linq的数学统计

leo*_*ora 14 c# linq

我有一组人物对象(IEnumerable),每个人都有一个年龄属性.

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

使用LINQ最优雅的方法是什么?

Ran*_*ard 34

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

    double? medianAge = people.Median(p => p.Age);
Run Code Online (Sandbox Code Playgroud)

当集合中没有非空值时,此实现返回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));
}
Run Code Online (Sandbox Code Playgroud)

  • 你是绝对正确的.并且 - 与LINQ一样 - 其影响范围从琐碎到禁止,取决于您的收藏的性质.记住优化规则:规则1:不要这样做.规则2(仅限专家):不要这样做.(参见http://blog.codinghorror.com/why-arent-my-optimizations-optimizing/) (3认同)

Ita*_*aro 28

var max = persons.Max(p => p.age);
var min = persons.Min(p => p.age);
var average = persons.Average(p => p.age);
Run Code Online (Sandbox Code Playgroud)

在偶数个元素的情况下修复中值

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;
Run Code Online (Sandbox Code Playgroud)

  • @Max你的时间最优解决方案在哪里? (4认同)

Ali*_*tad 10

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

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

中位数很容易:

UPDATE

我添加了订单:

ints.OrderBy(x=>x).Skip(ints.Count()/2).First();
Run Code Online (Sandbox Code Playgroud)

谨防

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

  • @Itay:不,这通常被称为medoid。*一个相关的概念,其中结果被迫对应于样本的成员是 medoid。* http://en.wikipedia.org/wiki/Median 您计算 medoid 的方式是有偏差的,因为它通常会返回一个低于中位数的值,永远不会返回一个高于中值的值。 (4认同)

Jos*_*hee 7

使用 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);
Run Code Online (Sandbox Code Playgroud)