6 Stimmen

Wie sortiert man eine generische Liste mit mehr als einer Eigenschaft?

Ich habe eine list-generic, die eine Eigenschaft (Klasse Typ) hat. Ich brauche eine Sortiermethode für Z-Parameter (TrainingSet):

public override List<TrainingSet> CalculatedDistancesArray
    (List<TrainigSet> ts, double x, double y, int k)
{
    for (int i =0; i < ts.Count; i++)
    {
        ts[i].Z = (Math.Sqrt(Math.Pow((ts[i].X - x), 2) 
                  + Math.Pow((ts[i].Y - y), 2)));
    }
    // I want to sort according to Z
    ts.Sort(); //Failed to compare two elements in the array.
    List<TrainingSet> sortedlist = new List<TrainingSet>();
    for (int i = 0; i < k; i++)
    {
        sortedlist.Add(ts[i]);
    }
    return ts;
}

public class TrainigSet
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
    public string Risk { get; set; }
}

0 Stimmen

Es gibt übrigens auch einfachere Möglichkeiten, eine Liste zu kopieren - und wollten Sie wirklich die Eingabe Liste und kopieren Sie sie dann in eine neue Liste?

0 Stimmen

Er kopiert nicht die gesamte Liste, sondern nur die ersten k Punkte.

20voto

Jon Skeet Punkte 1325502

Das Sortieren nach einer einzelnen Immobilie ist einfach. Verwenden Sie die Überladung, die eine Comparison<T> :

// C# 2
ts.Sort(delegate (TrainingSet o1, TrainingSet o2) 
       { return o1.Z.CompareTo(o2.Z)); }
);

// C# 3
ts.Sort((o1, o2) => o1.Z.CompareTo(o2.Z));

Das Sortieren nach mehreren Eigenschaften ist etwas schwieriger. Ich habe Klassen zu bauen, Vergleiche in einer zusammengesetzten Art und Weise, sowie Gebäude "Projektion Vergleiche", aber wenn Sie wirklich nur nach Z sortieren wollen, dann der obige Code wird so einfach wie es geht.

Wenn Sie .NET 3.5 verwenden und die Liste nicht unbedingt an Ort und Stelle sortiert werden muss, können Sie OrderBy und ThenBy verwenden, z. B.

return ts.OrderBy(t => t.Z);

oder für einen komplizierteren Vergleich:

return ts.OrderBy(t => t.Z).ThenBy(t => t.X);

Diese würden dargestellt werden durch orderby Klauseln in einem Abfrageausdruck:

return from t in ts
       orderby t.Z
       select t;

et

return from t in ts
       orderby t.Z, t.X
       select t;

(Sie können auch absteigend sortieren, wenn Sie möchten.)

3voto

mmx Punkte 400975
var sortedList = 
      list.OrderBy(i => i.X).ThenBy(i => i.Y).ThenBy(i => i.Z).ToList();

0 Stimmen

Beachten Sie, dass dies die Liste nicht an Ort und Stelle sortiert, was der OP Mai wollen - das ist nicht klar.

0 Stimmen

@ykaratoprak: Siehe die Antwort von Jon Skeet. Er hat eine 2.0-Version.

1voto

MyFriend Punkte 11

Versuchen Sie dies. Bei mir hat es funktioniert:

ts.Sort(delegate(TrainingSet a, TrainingSet b) { return a.X.CompareTo(b.X) != 0 ? a.X.CompareTo(b.X) : a.Y.CompareTo(b.Y); });

0voto

Guffa Punkte 663241

Bei Verwendung des Frameworks 3.5 würde dies einfach lauten:

public override List<TrainingSet> CalculatedDistancesArray(List<TrainigSet> ts, double x, double y, int k) {
   foreach (TrainigSet t in ts) {
      t.Z = Math.Sqrt(Math.Pow(t.X - x, 2) + Math.Pow(t.Y - y, 2));
   }
   return ts.OrderBy(t => t.Z).Take(k).ToList();
}

Hinweis: Dadurch wird die Reihenfolge der ts-Liste nicht geändert, sondern eine neue, sortierte Liste erstellt, die zurückgegeben wird.

(Ich nehme an, dass Sie tatsächlich die ersten k Elemente aus der Liste zurückgeben wollten, nicht die ts-Liste, wie Sie es in dem Code in Ihrer Frage tun).

Die Verwendung von Framework 2 erfordert ein wenig mehr Code:

public override List<TrainingSet> CalculatedDistancesArray(List<TrainigSet> ts, double x, double y, int k) {
   foreach (TrainigSet t in ts) {
      t.Z = Math.Sqrt(Math.Pow(t.X - x, 2) + Math.Pow(t.Y - y, 2));
   }
   ts.Sort(delegate (TrainigSet t1, TrainigSet t2) { return t1.Z.CompareTo(t2.Z)); });
   List<TrainigSet> result = new List<TrainigSet>(k);
   for (int i = 0; i < k ; i++) {
      result.Add(ts[i]);
   }
   return result;
}

Wenn Sie den Z-Wert nur für die Sortierung verwenden, können Sie die Math.Sqrt aufzurufen und als Wert einfach das Quadrat des Abstands anzugeben, da dieser Wert genau dem Abstand entspricht.

0voto

flq Punkte 21455

Sie können die Sortiermethode für die Liste verwenden, wenn Sie IComparable<TrainingSet> für Ihren Typ "TrainingSet" implementieren. Sie müssen eine "CompareTo"-Methode implementieren. Sie können Ihre Implementierung dann einfach an die "CompareTo"-Methode Ihres doppelt getypten Z delegieren, um die Ausnahme zu vermeiden.

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