2009-05-09 11 views
6

プロパティ(クラスタイプ)を持つリストジェネリックを持っています。私は、Zパラメータ(トレーニングセット)のソート方法が必要になります。2つ以上のプロパティの場合、リストタイプのジェネリックをソートする方法は?

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

ところで、リストをコピーする簡単な方法があることに注意してください - 本当に*入力*リストをソートし、それを新しいリストにコピーすることを意味しましたか? –

+0

彼はリスト全体をコピーせず、最初のk個のアイテムだけをコピーします。 – Guffa

答えて

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; 

(あなたは、できる 。また、ソート降順的にしたい場合)

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

Web 2.0コードが必要です。私はウェブ3.5を持っていません – Penguen

+0

これは、OP *が望むかもしれない場所にリストをソートしないことに注意してください - それは明確ではありません。 –

+0

@ykaratoprak:Jon Skeetの答えを参照してください。彼は2.0バージョンを持っています。 –

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リストの順序を変更しますが、新しい、ソートされたリストを作成しません復帰する。

(私はあなたが実際にあなたがあなたの質問のコードで行うよう、リストからではなく、TSリストを最初のk個のアイテムを返すように望んでいたことを想定しています。)フレームワーク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呼び出しをスキップ可能性があり、それは距離とまったく同じようにソートするだけで、距離の二乗する値のままにしておきます。

0

IComparable <TrainingSet>を "TrainingSet"の種類に実装すると、リストのSortメソッドを使用することができます。 "CompareTo"メソッドを実装する必要があります。次に、実装を二重型Zの "CompareTo"に委譲することができます。これにより、例外が回避されます。

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

コードをフォーマットします... – Rajesh

関連する問題