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

时间:2009-05-09 09:02:48

标签: c# .net asp.net generics

我有一个list-generic,它有一个属性(类类型)。我需要一个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; }
}

5 个答案:

答案 0 :(得分:20)

只需对单个属性进行排序即可。使用带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));

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

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

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

或进行更复杂的比较:

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

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

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

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

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

答案 1 :(得分:3)

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

答案 2 :(得分:1)

你可以试试这个。它对我有用:

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

答案 3 :(得分:0)

使用框架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();
}

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

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

使用框架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;
}

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

答案 4 :(得分:0)

如果您实现IComparable&lt; TrainingSet&gt;,则可以在列表中使用Sort方法。在您的类型“TrainingSet”上。您必须实现“CompareTo”方法。然后,您可以简单地将您的实现委托给双重类型Z的“CompareTo”。这将避免您的异常。