使用Linq进行数学统计

cotxawn7  于 2023-05-26  发布在  其他
关注(0)|答案(5)|浏览(159)

我有一个person对象的集合(IEnumerable),每个person都有一个age属性。
我想生成统计数据的收集,如最大,最小,平均,中位数等,对这个年龄属性。
使用LINQ最优雅的方式是什么?

kd3sttzy

kd3sttzy1#

下面是一个完整的、通用的Median实现,它可以正确处理空集合和可空类型。它是以Enumerable的风格LINQ友好的。平均,例如:

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

当集合中没有非空值时,此实现将返回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));
}
vzgqcmou

vzgqcmou2#

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;
lyfkaqu1

lyfkaqu13#

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并存储到一个变量中,或者直接使用它,会更好。

dw1jzc5e

dw1jzc5e4#

使用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);
hgb9j2n6

hgb9j2n65#

我的Median LINQ扩展,使用Generic Math(.NET 7+)

public static TSource Median<TSource>(this IEnumerable<TSource> source)
    where TSource : struct, INumber<TSource>
    => Median<TSource, TSource>(source);

public static TResult Median<TSource, TResult>(this IEnumerable<TSource> source)
    where TSource : struct, INumber<TSource>
    where TResult : struct, INumber<TResult>
{
    var array = source.ToArray();
    var length = array.Length;
    if (length == 0)
    {
        throw new InvalidOperationException("Sequence contains no elements.");
    }
    Array.Sort(array);
    var index = length / 2;
    var value = TResult.CreateChecked(array[index]);
    if (length % 2 == 1)
    {
        return value;
    }
    var sum = value + TResult.CreateChecked(array[index - 1]);
    return sum / TResult.CreateChecked(2);
}

相关问题