2013-01-09 45 views
6

Tôi có một danh sách chungSắp xếp một danh sách chung bởi một thứ tự sắp xếp bên ngoài

dụ Giản

var list = new List<string>() 
    { 
    "lorem1.doc", 
    "lorem2.docx", 
    "lorem3.ppt", 
    "lorem4.pptx", 
    "lorem5.doc", 
    "lorem6.doc", 
    }; 

Những gì tôi muốn làm là để sắp xếp những mục này dựa trên một danh sách bên ngoài đặt hàng

Ví dụ:

var sortList = new[] { "pptx", "ppt", "docx", "doc" }; 

// Or 
var sortList = new List<string>() { "pptx", "ppt", "docx", "doc" }; 

Có bất kỳ thứ gì gắn liền với linq có thể giúp tôi đau không eve này hoặc tôi phải đi theo cách foreach?

+0

Bạn muốn sắp xếp họ và giữ chúng trong một danh sách hoặc lấy lại nhóm sẽ có ích? – R0MANARMY

Trả lời

8

Với danh sách, bạn có thể sử dụng IndexOf cho Enumerable.OrderBy:

var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s))); 

Vì vậy, các chỉ số của phần mở rộng trong sortList xác định ưu tiên trong danh sách khác. Tiện ích mở rộng không xác định có mức độ ưu tiên cao nhất vì chỉ mục của chúng là -1.

Nhưng bạn cần phải thêm một dấu chấm để phần mở rộng để làm cho nó làm việc:

var sortList = new List<string>() { ".pptx", ".ppt", ".docx", ".doc" }; 

Nếu đó không phải là một lựa chọn bạn phải fiddle xung quanh với Substring hoặc Remove, ví dụ:

var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s).Remove(0,1))); 
+3

+1 cho giải pháp tốt và dejavu :) –

+1

Chỉ cần lưu ý rằng GetExtension() cũng trả về phần mở rộng "dấu chấm", trong khi sortList không có ... – digEmAll

+0

@digEmAll Nó nhận được phần mở rộng từ tên tập tin trong danh sách gốc (ví dụ, "lorem1.doc") –

6

Giải pháp này sẽ hoạt động ngay cả khi một số tên tệp không có phần mở rộng:

var sortList = new List<string>() { "pptx", "ppt", "docx", "doc" }; 
var list = new List<string>() 
    { 
    "lorem1.doc", 
    "lorem2.docx", 
    "lorem3.ppt", 
    "lorem4.pptx", 
    "lorem5.doc", 
    "lorem6.doc", 
    }; 

var result = 
     list.OrderBy(f => sortList.IndexOf(Path.GetExtension(f).Replace(".",""))); 
1

Bạn có thể thử sử dụng phương pháp Array.IndexOf():

var sortedList = list.OrderBy(i => sortList.IndexOf(System.IO.Path.GetExtension(i))).ToList(); 
1

Một sortDicionary sẽ hiệu quả hơn:

var sortDictionary = new Dictionary<string, int> { 
    { ".pptx", 0 }, 
    { ".ppt" , 1 }, 
    { ".docx", 2 }, 
    { ".doc" , 3 } }; 

var sortedList = list.OrderBy(i => { 
    var s = Path.GetExtension(i); 
    int rank; 
    if (sortDictionary.TryGetValue(s, out rank)) 
     return rank; 
    return int.MaxValue; // for unknown at end, or -1 for at start 
}); 

Bằng cách này, tra cứu là O(1) hơn O(# of extensions).

Ngoài ra, nếu bạn có một số lượng lớn các tên tập tin và một số ít các phần mở rộng, nó có thể thực sự được nhanh hơn để làm

var sortedList = list 
    .GroupBy(p => Path.GetExtension(p)) 
    .OrderBy(g => { 
     int rank; 
     if (sortDictionary.TryGetValue(g.Key, out rank)) 
      return rank; 
     return int.MaxValue; // for unknown at end, or -1 for at start 
    }) 
    .SelectMany(g => g); 

này có nghĩa là quy mô sắp xếp theo số lượng các phần mở rộng khác nhau trong đầu vào, thay vì số lượng mục trong đầu vào.

Điều này cũng cho phép bạn cung cấp cho hai tiện ích cùng mức độ ưu tiên.

0

Dưới đây là một cách khác mà không sử dụng OrderBy:

var res = 
sortList.SelectMany(x => list.Where(f => Path.GetExtension(f).EndsWith(x))); 

Lưu ý rằng sự phức tạp của phương pháp này là O(n * m) với n = sortList.Countm list.Count.

Các OrderBy cách tiếp cận hợp tồi tệ nhất phức tạp là thay vì O(n * m * log m) nhưng có lẽ nói chung nó sẽ nhanh hơn (vì IndexOf không dẫn luôn trong O(n)).Tuy nhiên, với số lượng nhỏ nm bạn sẽ không nhận thấy bất kỳ sự khác biệt nào.

Đối với danh sách lớn cách nhanh nhất (độ phức tạp O(n+m)) có thể xây dựng một tạm thời tra cứu ví dụ:

var lookup = list.ToLookup(x => Path.GetExtension(x).Remove(0,1)); 
var res = sortList.Where(x => lookup.Contains(x)).SelectMany(x => lookup[x]); 
Các vấn đề liên quan