views:

1017

answers:

4

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  A: 
var sortedList = 
      list.OrderBy(i => i.X).ThenBy(i => i.Y).ThenBy(i => i.Z).ToList();
Mehrdad Afshari
i need web 2.0 codes. i don't have web 3.5
Phsika
Note that this doesn't sort the list in place, which the OP *may* want - it's not clear.
Jon Skeet
@ykaratoprak: See Jon Skeet's answer. He has a 2.0 version.
Mehrdad Afshari
+8  A: 

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

Jon Skeet
A: 

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.

Guffa
A: 

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.

flq