24 Stimmen

Mathematik-Statistiken mit Linq

Ich habe eine Sammlung von Person Objekte (IEnumerable) und jede Person hat eine Alter Eigentum.

Ich möchte Statistiken über die Sammlung wie Max, Min, Average, Median, etc. für diese Alterseigenschaft erstellen.

Was ist die eleganteste Art, dies mit LINQ zu tun?

1 Stimmen

Seien Sie vorsichtig, wenn die Daten aus einer Datenbank kommen, wie Linq die Daten mehr als einmal lesen kann, jedoch in Ihrem Fall Linq sollte ein gutes Werkzeug sein, wie Sie scheinen, um Ihre Sammlung in ram haben.

45voto

Rand Scullard Punkte 2687

Hier ist eine vollständige, generische Implementierung von Median, die leere Sammlungen und nullable Typen richtig behandelt. Sie ist LINQ-freundlich, zum Beispiel im Stil von Enumerable.Average:

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

Diese Implementierung gibt null zurück, wenn es keine Werte in der Sammlung gibt, die nicht null sind, aber wenn Sie den Rückgabetyp nullable nicht mögen, können Sie ihn leicht ändern, um stattdessen eine Ausnahme zu erzeugen.

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

0 Stimmen

Dies, AFAIK, zählt die Quelle 2 oder 3 Mal auf: zuerst wenn Count() aufgerufen wird, das zweite (und möglicherweise dritte) Mal, wenn ElementAt aufgerufen wird.

9 Stimmen

Sie haben völlig Recht. Und - wie immer bei LINQ - die Auswirkungen reichen von trivial bis prohibitiv, je nach Art Ihrer Sammlung. Denken Sie an die Regeln der Optimierung: Regel 1: Tun Sie es nicht. Regel 2 (nur für Experten): Tun Sie es noch nicht. (Siehe blog.codinghorror.com/why-arent-my-optimizations-optimizing )

31voto

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

Fix für Median bei gerader Anzahl von Elementen

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;

1 Stimmen

An dieser Stelle sei angemerkt, dass dieser Algorithmus nicht zeitoptimal ist. Der Median kann in O(n)-Zeit berechnet werden.

6 Stimmen

@Max Wo ist Ihre zeitoptimale Lösung?

11voto

Aliostad Punkte 78595

Max, Min, Average sind Teil von Linq:

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

Der Median ist einfach:

UPDATE

Ich habe Ordnung hinzugefügt:

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

HINWEIS

Alle diese Vorgänge werden in einer Schleife ausgeführt. Zum Beispiel, ints.Count() ist eine Schleife, so dass, wenn Sie bereits erhalten ints.Length und in einer Variablen gespeichert oder einfach verwenden Sie es, wie es ist, wäre besser.

1 Stimmen

ints.ElementAt(ints.Count()/2)

0 Stimmen

Damit der Median richtig ist, müssen Sie das Feld zuerst ordnen.

1 Stimmen

Ihre Implementierung von Median geht ebenfalls davon aus, dass die Eingabe eine ungerade Anzahl von Elementen hat. Sie schlägt fehl bei {0, 1} (es wird 0 statt 0,5 ergeben).

4voto

Josh Withee Punkte 7862

Abrufen des Medians mit Linq (funktioniert für eine gerade oder ungerade Anzahl von Elementen)

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X