2009-05-09 60 views
6

Tôi có danh sách chung chung có thuộc tính (loại lớp). Tôi cần một cách sắp xếp cho các thông số Z (TrainingSet):Cách sắp xếp loại danh sách chung chung nếu có nhiều thuộc tính?

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

Lưu ý rằng có nhiều cách sao chép danh sách dễ dàng hơn - và bạn có thực sự muốn sắp xếp danh sách * đầu vào và sau đó sao chép nó vào danh sách mới? –

+0

Anh ấy không sao chép toàn bộ danh sách, chỉ có các mục k đầu tiên. – Guffa

Trả lời

20

Chỉ cần sắp xếp trên một tài sản duy nhất là dễ dàng. Sử dụng quá tải phải mất một 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)); 

Sắp xếp trên nhiều thuộc tính phức tạp hơn một chút. Tôi đã có các lớp để xây dựng các so sánh theo cách phức tạp, cũng như xây dựng "so sánh chiếu" nhưng nếu bạn thực sự chỉ muốn sắp xếp theo Z thì mã trên sẽ dễ dàng như nó được.

Nếu bạn đang sử dụng .NET 3.5 và bạn không thực sự cần danh sách được sắp xếp tại chỗ, bạn có thể sử dụng OrderBy và ThenBy, ví dụ:

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

hoặc để so sánh phức tạp hơn:

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

Những sẽ được đại diện bởi orderby khoản trong một biểu thức truy vấn:

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

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

(Bạn có thể . Cũng loại một cách giảm dần nếu bạn muốn)

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

tôi cần mã web 2.0. Tôi không có web 3.5 – Penguen

+0

Lưu ý rằng điều này không sắp xếp danh sách tại chỗ, mà OP * có thể * muốn - nó không rõ ràng. –

+0

@ykaratoprak: Xem câu trả lời của Jon Skeet. Anh ấy có phiên bản 2.0. –

0

Sử dụng framework 3.5 này sẽ chỉ đơn giản là:

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

Lưu ý: Điều này sẽ không thay đổi thứ tự của danh sách ts, nhưng tạo ra một mới, sắp xếp danh sách trở về.

(tôi giả sử rằng bạn thực sự muốn trở lại các mục k đầu tiên trong danh sách, không phải là danh sách ts như bạn làm trong các mã trong câu hỏi của bạn.)

Sử dụng khuôn khổ 2 cần nhiều mã một chút:

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

Nếu bạn chỉ sử dụng giá trị Z để sắp xếp, bạn có thể bỏ qua cuộc gọi Math.Sqrt và chỉ để lại giá trị làm hình vuông của khoảng cách, như sắp xếp chính xác như khoảng cách.

0

Bạn sẽ có thể sử dụng phương thức Sắp xếp trong danh sách nếu bạn triển khai IComparable <TrainingSet> về loại "TrainingSet" của mình. Bạn sẽ phải thực hiện một phương pháp "CompareTo". Sau đó, bạn có thể chỉ ủy nhiệm triển khai của mình cho "CompareTo" của chữ Z kép của bạn. Điều này sẽ tránh ngoại lệ của bạn.

1

Bạn có thể thử điều này. Nó làm việc cho tôi:

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

Định dạng mã lệnh của bạn ... – Rajesh

Các vấn đề liên quan