2012-08-25 36 views
5

Hãy tưởng tượng rằng bạn có một danh sách được gọi là List<Foo>.Cách đặt danh sách theo loại?

Foo là lớp trừu tượng, vì vậy, đây có thể là FooA, FooB, FooC hoặc FooD. Và tôi muốn có một phần mở rộng cho List<T>, nơi bạn có thể đặt hàng các yếu tố này theo loại nhưng theo thứ tự.

Ví dụ: nếu tôi có 9 phần tử trong đó.

FooA, FooA, FooB, FooD, FooC, FooC, FooA, FooB, FooA 

Sắp xếp theo loại liên tiếp sẽ là.

FooA, FooB, FooC, FooD, FooA, FooB, FooC, FooA, FooA 

Tôi đang cố gắng rằng chức năng có thể được đặt theo lệnh bạn chỉ định, ở trường hợp này, IE, đó là:

new[] { typeof(FooA), typeof(FooB), typeof(FooC), typeof(FooD) } 

Tôi đã cố gắng để tạo ra phần mở rộng này, nhưng tôi don 't nhận được bất cứ điều gì. Bạn có thể giúp một chút không? Tôi đoán rằng tôi có thể thực hiện nó với LINQ.

+0

điều gì xảy ra nếu không có FooC trong danh sách hoặc có FooA, FooB, FooC, FooC, FooC, FooD, bạn sắp xếp như thế nào? tôi sẽ khuyên bạn nên thích ứng lựa chọn sắp xếp cho các mục đích của bạn. – DarthVader

Trả lời

6

Bạn có thể nhóm các mặt hàng theo loại, sắp xếp các nhóm theo loại và interleave các nhóm:

var groups = items.GroupBy(x => x.GetType()) 
        .OrderBy(g => orderedTypes.IndexOf(g.Key)) 
        .ToList(); 

var result = groups.First().Interleave(groups.Skip(1).ToArray()); 

sử dụng Interleave method from EvenMoreLINQ.

foreach (var item in result) 
{ 
    Console.WriteLine(item.GetType()); 
} 

Output:

FooA 
FooB 
FooC 
FooD 
FooA 
FooB 
FooC 
FooA 
FooA 
1

Nhóm vào loại, sau đó vòng qua các mục để thêm một bộ mỗi lần. Một cái gì đó như:

var groups = 
    collection.GroupBy(x => x.GetType()) 
    .ToDictionary(g => g.Key, g => g.ToList()); 

List<Foo> result = new List<Foo>(); 
int max = groups.Values.Max(n => n.Count); 
for (int i = 0; i < max; i++) { 
    foreach (Type t in sortArray) { 
    if (groups[t].Count > i) { 
     result.Add(groups[t][i]); 
    } 
    } 
} 
+0

'sortArray' là gì? –

+0

@ L.B: Mảng các đối tượng 'Loại' chỉ định thứ tự sắp xếp. – Guffa

0

list là tập hợp các yếu tố cần sắp xếp.
pattern là tập hợp các phần tử theo thứ tự cụ thể.
result là tập hợp các yếu tố từ list được đặt hàng theo số pattern.

var list = new List<Foo> { new FooA(), new FooB(), new FooC(), new FooA(), new FooC(), new FooA(), new FooD() }; 
var pattern = new Foo[] { new FooB(), new FooC(), new FooD(), new FooA() }; 

var result = list.OrderBy(p => p, new MyFooComparer(pattern)); 

Có một lớp MyFooComparer mà thực hiện giao diện IComparer<>.
So sánh dựa trên vị trí của từng bộ sưu tập Foo trong bộ sưu tập pattern. Các yếu tố patternkhông được nhân đôi và chúng phải chứa tất cả các loại Foo (ít nhất là các loại được sử dụng trong list).
Tôi đã sử dụng Dictionary<> để lưu trữ thứ tự mẫu vì nó có độ phức tạp O (1).

public class MyFooComparer : IComparer<Foo> 
{ 
    private readonly Dictionary<Type, int> _pattern; 
    public MyFooComparer(IEnumerable<Foo> pattern) 
    { 
     _pattern = new Dictionary<Type, int>(); 
     int i = 0; 
     foreach (var foo in pattern) 
     { 
      _pattern.Add(foo.GetType(), i); 
      i++; 
     } 
    } 

    public int Compare(Foo x, Foo y) 
    { 
     var xVal = _pattern[x.GetType()]; 
     var yVal = _pattern[y.GetType()]; 
     return xVal.CompareTo(yVal); 
    } 
} 

Sau khi gọi:

 foreach (var foo in result) 
     { 
      Console.WriteLine(foo.GetType().Name); 
     } 

Theo pattern, bạn sẽ nhận được:

FooB 
FooC 
FooC 
FooD 
FooA 
FooA 
FooA 

EDIT:

Extension for List<Foo>:

static class MyExtension 
{ 
    public static IEnumerable<Foo> OrderByFoo<T>(this List<Foo> list, IEnumerable<Foo> patern) 
    { 
     return list.OrderBy(p => p, new MyFooComparer(patern)); 
    } 
} 
Các vấn đề liên quan