2010-10-03 72 views
6

Tôi có một truy vấn trong linqtosql mà trả về một LabelNumber:C# LINQ Tuỳ chỉnh Sắp xếp

var q = from list in db.Lists 
     select list.LabelNumber; 

var q sau đó trở thành một IEnumerable<string> với các yếu tố như thế này:

{"1","2","2.A","2.B","3","3.A","3.B"} 

tôi về cơ bản muốn đặt hàng các yếu tố như chúng xuất hiện ở trên, nhưng tôi không thể sử dụng OrderBy(x=>x.LabelNumber)"10" sẽ được đặt sau "1" và trước "2".

Tôi cho rằng tôi phải viết một hàm so sánh tùy chỉnh, nhưng làm cách nào để làm điều này với LINQ?

Chỉnh sửa: Tôi nghĩ rằng tất cả các câu trả lời bên dưới sẽ hiệu quả, nhưng bạn phải thêm một báo trước cho tất cả các câu trả lời.

Nếu bạn đang sử dụng Linq2SQL, bạn không thể sử dụng chỉ mục mảng trong truy vấn. Để khắc phục điều này, bạn cần có hai truy vấn. Một trong đó đọc từ SQL. Thứ hai không thứ tự:

var q = from list in db.Lists 
      select list.LabelNumber; 

var q2 = q.AsEnumerable() 
      .OrderBy(x => int.Parse(x.LabelNumber.Split('.')[0])) 
      .ThenBy(x => x.Number 
         .Contains(".") ? 
           x.LabelNumber.Split('.')[1].ToString() 
           : 
           string.Empty); 
+0

FYI, sắp xếp các con số theo cách bạn muốn được gọi là "loại tự nhiên". – mquander

Trả lời

9

Bạn có lẽ không phải viết một comparer tùy chỉnh. Nếu tất cả các nhãn của bạn ở dạng number.letter, bạn có thể sử dụng nhãn này.

Nếu bạn cần kiểm soát nhiều hơn, bạn luôn có thể chuyển đổi các lĩnh vực SortBy (ab) cho các loại thích hợp hơn là ints và chuỗi.


Nếu đây là LINQ to SQL, điều này thực sự sẽ không hoạt động vì một số phương pháp được sử dụng tại đây không được hỗ trợ. Đây là phiên bản thân thiện với LINQ to SQL. Nó sẽ không mang lại truy vấn đẹp nhất, nhưng nó sẽ hoạt động.

var query = from list in db.Lists 
      let dot = list.LabelNumber.IndexOf('.') 
      let name = list.LabelNumber 
      let order = dot == -1 
       ? new { a = Convert.ToInt32(name.Substring(0, dot)), b = String.Empty } 
       : new { a = Convert.ToInt32(name.Substring(0, dot)), b = name.Substring(dot+1) } 
      orderby order.a, order.b 
      select list.LabelNumber; 
+0

Tôi nhận được lỗi này khi tôi chạy lệnh này: 'System.InvalidOperationException: Nút biểu thức không được nhận dạng: ArrayIndex' – Shawn

+0

Đây là quyền LINQ-to-SQL? Tất nhiên điều này sẽ không làm việc ở đó và sẽ yêu cầu một số tinh chỉnh. –

+0

Tôi đã thêm một bản chỉnh sửa để xử lý tinh chỉnh. cảm ơn. – Shawn

1

Nếu bạn chắc chắn rằng q là định dạng tốt và trình tự:

var result = q.OrderBy(x => int.Parse(x.Split('.')[0])); 
+2

Bạn đang giả định rằng chỉ những con số không đúng thứ tự. Nếu bạn có 2.B, 2,2.A thì sao? –

+0

@Michael: OP đã không nói rằng anh ấy muốn đặt hàng các chữ cái ... và tôi đủ lười biếng. Dù sao thì nó cũng có khả năng là anh ta muốn nó. LOL. –

11
OrderBy(x=>x.LabelNumber, new AlphanumComparator()) 

nơi AlphanumComparator là tuyệt vời Alphanum natural sort algorithm David Koelle. Không cần phải phát minh lại bánh xe.

Nếu bạn đang gonna sử dụng phiên bản C# thay đổi nó thành:

AlphanumComparator : IComparer<string> 

public int Compare(string x, string y) 
+3

+1, để giới thiệu tôi với AlphanumComparator –

+0

Cú pháp này không hoạt động. 'Đối số 3: không thể chuyển đổi từ 'AlphanumComparator' thành 'System.Collections.Generic.IComparer '' – Shawn

+0

Đó là do OrderBy mong đợi một IComparer chung, trong khi AlphanumComparator là không chung chung. Tuy nhiên, sự thay đổi này khá dễ thực hiện. Thêm 's trong các tờ khai, thay đổi tất cả các đối tượng để Ts và loại bỏ phôi. – Kyte

0

Dưới đây là những đóng góp của tôi .. sử dụng Regular ExpressionLAMBDA expression

List<String> Lst = new List<string> { "1", "2", "2.A","10.A", "2.C", "3", "3.A", "3.B","2.B","11.D" }; 
Lst = Lst.Select(X => new 
     { 
      Number = int.Parse(Regex.Match(X, @"([0-9]*).?([a-zA-Z]*)").Groups[1].Value), 
      Strings=Regex.Match(X, @"([0-9]*).?([a-zA-Z]*)").Groups[2].Value, 
      OriginalString = X 
     }).OrderBy(X => X.Number).ThenBy(X=>X.Strings) 
     .Select(X => X.OriginalString).ToList(); 

Output :

"1" 
"2" 
"2.A" 
"2.B" 
"2.C" 
"3" 
"3.A" 
"3.B" 
"10.A" 
"11.D" 
+0

'Phương thức 'System.Text.RegularExpressions.Match Match (System.String, System.String)' không có bản dịch được hỗ trợ cho SQL.' Mặc dù nó dường như hoạt động trong ví dụ của bạn. – Shawn

+0

sau đó tạo một 'danh sách' với các nhãn của bạn và sau đó sắp xếp bằng cách sử dụng biểu thức trên. –

+0

Đã giải quyết. Cảm ơn, tôi đã cho bạn mã chạy với Linq2SQL. Tôi không biết về giới hạn mảng. Tôi đã kết thúc bằng cách sử dụng một phiên bản đơn giản, như regex trên phức tạp tình hình của tôi. Các tổ phụ cuối cùng sẽ nhận được phức tạp hơn và tôi sẽ phải nghỉ mát để giải pháp của bạn. Cảm ơn. – Shawn