How to sort list type generic if more than one property?

时光总嘲笑我的痴心妄想 提交于 2021-02-07 06:49:15

问题


I have a list-generic that has a property (class type). I need a sort method for Z parameters (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; }
}

回答1:


Just sorting on a single property is easy. Use the overload which takes a 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));

Sorting on multiple properties is a bit trickier. I've got classes to build up comparisons in a compound manner, as well as building "projection comparisons" but if you really only want to sort by Z then the above code is going to be as easy as it gets.

If you're using .NET 3.5 and you don't really need the list to be sorted in-place, you can use OrderBy and ThenBy, e.g.

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

or for a more complicated comparison:

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

These would be represented by orderby clauses in a query expression:

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

and

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

(You can also sort in a descending manner if you want.)




回答2:


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



回答3:


You could try this. It worked for me:

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



回答4:


Using framework 3.5 this would simply be:

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

Note: This will not change the order of the ts list, but create a new, sorted list to return.

(I assume that you actually wanted to return the first k items from the list, not the ts list as you do in the code in your question.)

Using framework 2 needs a little more 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;
}

If you are using the Z value only for the sorting, you could skip the Math.Sqrt call and just leave the value to be the square of the distance, as that sorts exactly the same as the distance.




回答5:


You will be able to use the Sort method on the list if you implement IComparable<TrainingSet> on your type "TrainingSet". You will have to implement a "CompareTo" method. You can then simply delegate your implementation to the "CompareTo" of your double-typed Z. This will avoid your exception.



来源:https://stackoverflow.com/questions/842998/how-to-sort-list-type-generic-if-more-than-one-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!