C# 如果有多个属性,如何对列表类型进行排序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/842998/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:50:02  来源:igfitidea点击:

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

c#.netasp.netgenerics

提问by Penguen

I have a list-generic that has a property (class type). I need a sort method for Z parameters (TrainingSet):

我有一个具有属性(类类型)的列表泛型。我需要一个 Z 参数的排序方法(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; }
}

采纳答案by Jon Skeet

Just sorting on a single property is easy. Use the overload which takes a Comparison<T>:

只需对单个属性进行排序就很容易。使用需要 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.

对多个属性进行排序有点棘手。我有一些类可以以复合方式建立比较,以及建立“投影比较”,但如果您真的只想按 Z 排序,那么上面的代码将变得非常简单。

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.

如果您使用的是 .NET 3.5 并且您真的不需要就地对列表进行排序,则可以使用 OrderBy 和 ThenBy,例如

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 orderbyclauses in a query expression:

这些将由orderby查询表达式中的子句表示:

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

(如果需要,您也可以按降序排序。)

回答by Mehrdad Afshari

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

回答by Guffa

Using framework 3.5 this would simply be:

使用框架 3.5 这将是:

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.

注意:这不会改变 ts 列表的顺序,而是创建一个新的、排序的列表来返回。

(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.)

(我假设您实际上想从列表中返回前 k 个项目,而不是像您在问题代码中所做的那样返回 ts 列表。)

Using framework 2 needs a little more code:

使用框架 2 需要多一点代码:

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.Sqrtcall and just leave the value to be the square of the distance, as that sorts exactly the same as the distance.

如果您仅将 Z 值用于排序,则可以跳过Math.Sqrt调用并将值保留为距离的平方,因为排序与距离完全相同。

回答by flq

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.

如果您在您的类型“TrainingSet”上实现 IComparable<TrainingSet>,您将能够使用列表中的 Sort 方法。您将不得不实施“CompareTo”方法。然后您可以简单地将您的实现委托给您的双类型 Z 的“CompareTo”。这将避免您的异常。

回答by MyFriend

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