2010-10-06 43 views
6

Tôi có một bộ sưu tập như thế này,Làm thế nào để sắp xếp một bộ sưu tập dựa trên loại trong LINQ

Class Base{} 
Class A : Base {} 
Class B : Base {} 

List<Base> collection = new List<Base>(); 
collection.Add(new A()); 
collection.Add(new B()); 
collection.Add(new A()); 
collection.Add(new A()); 
collection.Add(new B()); 

Bây giờ tôi muốn sắp xếp bộ sưu tập dựa trên loại (A/B). Làm thế nào tôi có thể làm điều này? Làm ơn giúp tôi.

Trả lời

7

Bạn có thể sử dụng các loại thông tin chính nó:

collection.Sort((a,b) => 
    { 
     bool aType = a.GetType() == typeof(A); 
     bool bType = b.GetType() == typeof(A); 
     return aType.CompareTo(bType); 
    }); 

Điều này sẽ làm việc cho hai loại bạn chỉ định, nhưng không vượt quá phạm vi chúng. Nó cho phép bạn xác định thứ tự một cách rõ ràng (ví dụ: nếu bạn muốn các phần tử "B" trước "A", bạn có thể làm cho nó hoạt động bằng cách sử dụng kỹ thuật này).

Nếu bạn cần hỗ trợ nhiều loại, và thứ tự không cần phải được xác định trước, bạn có thể làm một cái gì đó như:

collection.Sort((a,b) => a.GetType().FullName.CompareTo(b.GetType().FullName)); 

này sẽ xử lý bất kỳ số lượng các loại (ví dụ: C và một loại phụ D cũng vậy, và sắp xếp chúng theo tên đầy đủ của chúng.

+0

@Anthony: Có - không có kiểm tra ở đây cho null. Ngay bây giờ, bất cứ điều gì khác ngoài A hoặc B cũng sẽ được coi là B, ... –

+0

Vâng, tôi đã xem xét nó, và hóa ra nó không * chính xác * những gì tôi sẽ đi xa vì không tính toán loại ' C: Base'. Tôi có thể làm 'a.GetType(). Name.CompareTo (b.GetType(). Name') (và bất kỳ kiểm tra null nào, chúng có liên quan không). Nhưng ai biết được, có lẽ chỉ có hai loại, và có lẽ 'A' thực sự là' Foo' và 'B' thực sự là' Bar' và 'Foo' nên đến trước 'Bar'. –

+0

@Anthony: Có thực sự không đủ thông tin trong câu hỏi ban đầu để hoàn toàn xác định điều này - điều này cho phép bạn kiểm soát nhiều hơn về cách sắp xếp xảy ra, nhưng thật khó để biết OP thực sự muốn gì ... –

0

EDIT: Tôi nghĩ rằng đây là những gì bạn muốn:

Nếu bạn không nhớ sắp xếp 'ra khỏi vị trí và giao lại danh sách, điều này sẽ làm việc:

collection = collection.GroupBy(item => item.GetType()) 
         .SelectMany(g => g) 
         .ToList(); 

hoặc tùy thuộc vào bạn nhu cầu, một cái gì đó như:

collection = collection.OrderBy(item => item.GetType().FullName) 
         .ToList(); 

Nếu nó phải ở đúng vị trí, sau đó viết so sánh tùy chỉnh và list.Sort có lẽ là lựa chọn tốt nhất.


Để nhóm các mặt hàng theo loại, bạn có thể sử dụng GroupBy:

var groupedItems = collection.GroupBy(item => item.GetType()); 

này sử dụng thực hiện chậm.

Ngoài ra, bạn có thể đặt các 'nhóm' thành một cấu trúc dữ liệu như thế này:

var itemsByTypeLookUp = collection.ToLookup(item => item.GetType()); 

foreach(A a in itemsByTypeLookUp[typeof(A)]) 
{ 
    ... 
} 

Nếu bạn chỉ tìm kiếm một loại nhất định:

var itemsOfTypeA = collection.OfType<A>(); 
+0

này nhóm họ, nhưng doens't sắp xếp danh sách ... –

+0

@ Reed Copsey: Cảm ơn, thay đổi nội dung. – Ani

1

Liệu

collection.Where(entry => entry is A).Concat(collection.Where(entry => entry is B)) 

làm những gì bạn cần?

1

Điều này sẽ đặt hàng để A sẽ là lần đầu tiên và B giây.

var xx = list.OrderBy(x => x.GetType() == typeof(B)).ToList(); 

dự án console sau này khẳng định:

class Program 
{ 
    public class X { } 
    public class A : X { } 
    public class B : X { } 
    static void Main() 
    { 
     List<X> list = new List<X>(); 
     list.Add(new B()); 
     list.Add(new A()); 
     list.Add(new B()); 
     list.Add(new A()); 
     list.Add(new A()); 

     // A.GetType() == typeof(B) will be "0" making the type A go first 
     // B.GetType() == typeof(B) will be "1" making the type B go last 
     var xx = list.OrderBy(x => x.GetType() == typeof(B)).ToList(); 

     Console.ReadLine(); 
    } 
} 

Trong trường hợp này tôi giả sử bạn chỉ có AB. Nếu bạn có nhiều loại, bạn sẽ phải tạo một bộ so sánh để trả về một giá trị cho mỗi loại.Bạn cũng có thể có một thuộc tính trong lớp cơ sở mà sẽ thiết lập thứ tự của các phần tử, sau đó bạn có thể sắp xếp danh sách với thuộc tính này.

+0

Điều gì sẽ xảy ra nếu có kiểu 'C: Base'? –

+0

@Anthony: Anh ta sẽ phải xử lý từng loại với một 'Comparer'. Trừ khi lớp cơ sở có một thuộc tính được gọi là 'Order' và bạn có thể đặt hàng bởi thuộc tính này. Vì anh ta chỉ nói 'A' và' B' tôi tin đây là giải pháp ngắn nhất cho anh ta. – BrunoLM

+0

@Jon Hanna cung cấp một cách thú vị để xử lý đơn đặt hàng, với một chức năng khác và bạn có thể cung cấp bất kỳ chỉ mục nào bạn muốn. Tất nhiên, chức năng đó sẽ phải được sửa đổi với mỗi loại mới. Hoặc, trong trường hợp của bạn, bạn có thể đặt hàng bằng 'x => x.GetType(). Tên', sẽ đặt A trước B trước C. Tất nhiên, có thể là A và B không thực sự là A và B và sắp xếp chữ cái sẽ không hoạt động. Vì vậy, có, chặn thêm thông tin, thật khó để nói câu trả lời là phù hợp. Tôi chỉ ném ra lớp C như một ý nghĩ. –

6
private static int OrderOnType(Base item) 
{ 
    if(item is A) 
    return 0; 
    if(item is B) 
    return 1; 
    return 2; 
} 

Sau đó, đưa đón bạn từ:

collection.OrderBy(OrderOnType) 

hoặc

collection.Sort((x, y) => OrderOnType(x).CompareTo(OrderOnType(y))); 

Tùy thuộc vào việc bạn muốn tại chỗ sắp xếp hay không. Bạn có thể đặt OrderOnType vào lambda nếu bạn thực sự muốn, nhưng điều này có vẻ dễ đọc hơn đối với tôi và tôi thích giữ lambdas hơn khi họ thêm thay vì giảm khả năng đọc.

4
collection.OrderBy(i => i.GetType() == typeof(A) ? 0 : 1); 

sẽ cung cấp cho bạn một chuỗi với tất cả các A s sau đó tất cả các B s

+0

Nếu có loại 'C: Base' thì sao? –

+0

@Anthony Pegram - Sau đó, cách tiếp cận này sẽ không hoạt động. Tôi cho rằng bạn có thể đặt hàng trên tên Loại, nhưng sau đó nếu bạn muốn thứ tự là A, C, B trong trường hợp đó thì sao? Nếu phương pháp này quá đơn giản, câu hỏi cần thêm chi tiết. – Lee

+0

Tôi đồng ý. Đó là một bài tập suy nghĩ.Dựa trên nhận xét của Jai ​​về câu trả lời của Reed, chỉ có 2 loại, điều này làm cho một số câu trả lời phù hợp. –

0

Something như thế này làm việc cho tôi.

collection.OrderBy(p => p.GetType().Equals(typeof(B))).ThenBy(p => p.GetType().Equals(typeof(A))).ToList(); 

Mã của tôi:

class Employer; 
class Doctor : Employer 
class Administrator : Employer 
class Nurse : Employer 
List<Employer> collection = new List<Employer>(); 
collection.Add(new Doctor()); 
collection.Add(new Administrator()); 
collection.Add(new Doctor()); 
collection.Add(new Nurse()); 
collection.Add(new Administrator()); 
collection = collection.OrderBy(p => p.GetType().Equals(typeof(Nurse))).ThenBy(p => p.GetType().Equals(typeof(Doctor))).ThenBy(p => p.GetType().Equals(typeof(Administrator))).ToList(); 
Các vấn đề liên quan