Математическая статистика с Linq

У меня есть коллекция объектов person (IEnumerable), и каждый человек имеет свойство age.

Я хочу создать статистику по коллекции, такую ​​как Max, Min, Average, Median и т.д. в этом возрасте.

Каков самый элегантный способ использования LINQ?

Ответы

Ответ 1

max - persons.Max(p => p.age);
min - persons.Min(p => p.age);
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

Вот полная, общая реализация медианы, которая правильно обрабатывает пустые коллекции и типы с нулевым значением. Это LINQ-friendly в стиле Enumerable.Average, например:

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

Эта реализация возвращает null, когда в коллекции нет ненулевых значений, но если вам не нравится тип возвращаемого значения nullable, вы можете легко изменить его, чтобы вместо этого сделать исключение.

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));
}

Ответ 3

Max, Min, Average являются частью Linq:

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

Медиана проста:

UPDATE

Я добавил порядок:

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

BEWARE

Все эти операции выполняются в цикле. Например, ints.Count() - это цикл, поэтому, если вы уже получаете ints.Length и сохраняетесь в переменной или просто используете его как есть, было бы лучше.