2012-01-23 35 views
8

Tôi có nhiều chương khác nhau với các độ sâu khác nhau.Sắp xếp các nội dung chương như 14.1.2.3 và 14.10.1.2.3.4

để có 14.1 và 14.4.2 và 14.7.8.8.2 v.v.

Sắp xếp chữ số và số 14.10 sẽ xuất hiện trước 14.2. Thật tồi tệ. Nó sẽ đến sau 14.9.

Có cách nào dễ dàng để sắp xếp, không thêm số 0 đứng đầu không? f.e. với LINQ?

+2

Tôi nghĩ câu trả lời được chấp nhận [ở đây] (http://stackoverflow.com/questions/6248039/how-to-sort-list-of-ip-addresses-using-c-sharp) cũng hợp lệ cho trường hợp của bạn. Mặc dù bạn sẽ bị giới hạn ở bốn "cấp độ". –

+0

trông khá đẹp, 4 cấp độ - ok. Ý tưởng cho nhiều hơn vẫn sẽ được tốt đẹp :) – Harry

Trả lời

7
public class NumberedSectionComparer : IComparer<string> 
{ 
    private int Compare(string[] x, string[]y) 
    { 
    if(x.Length > y.Length) 
     return -Compare(y, x);//saves needing separate logic. 
    for(int i = 0; i != x.Length; ++i) 
    { 
     int cmp = int.Parse(x[i]).CompareTo(int.Parse(y[i])); 
     if(cmp != 0) 
     return cmp; 
    } 
    return x.Length == y.Length ? 0 : -1; 
    } 
    public int Compare(string x, string y) 
    { 
    if(ReferenceEquals(x, y))//short-cut 
     return 0; 
    if(x == null) 
     return -1; 
    if(y == null) 
     return 1; 
    try 
    { 
     return Compare(x.Split('.'), y.Split('.')); 
    } 
    catch(FormatException) 
    { 
     throw new ArgumentException(); 
    } 
    } 
} 
+0

Công trình này! Tôi thích phong cách bạn đã giải quyết nó. Cảm ơn. – Harry

4

tôi đã làm điều này ngay bây giờ, cần một số xét nghiệm:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace TestesConsole 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] vers = new[] 
           { 
            "14.10", 
            "14.9", 
            "14.10.1", 
           }; 


      var ordered = vers.OrderBy(x => x, new VersionComparer()).ToList(); 

     } 
    } 

    public class VersionComparer : IComparer<string> 
    { 
     public int Compare(string x, string y) 
     { 
      string[] xs = x.Split('.'); 
      string[] ys = y.Split('.'); 

      int maxLoop = Math.Min(xs.Length, ys.Length); 

      for (int i = 0; i < maxLoop; i++) 
      { 
       if(int.Parse(xs[i]) > int.Parse(ys[i])) 
       { 
        return 1; 
       } 
       else if(int.Parse(xs[i]) < int.Parse(ys[i])) 
       { 
        return -1; 
       } 
      } 

      if(xs.Length > ys.Length) 
      { 
       return 1; 
      } 
      else if(xs.Length < ys.Length) 
      { 
       return -1; 
      } 

      return 0; 
     } 
    } 
} 
+0

Tôi đã thử nghiệm giải pháp này đầu tiên, và đối với một số lý do nó chạy trong xử lý lớn kết thúc với thời gian thực hiện tối đa ... Cảm ơn bạn rất nhiều thời gian của bạn, nhưng đối với tôi, vì một số lý do bí ẩn nó không hoạt động tốt. : | – Harry

+0

Tôi đã không kiểm tra tải, chỉ vì tò mò, bạn có bao nhiêu itens trong bộ sưu tập của bạn? –

+0

Có khoảng 1500 mục riêng biệt, 1700 hoặc một cái gì đó trong tổng số :) @fujiy – Harry

1
var headers = new List<string> {"14.1.2.3", "14.1", "14.9", "14.2.1", "14.4.2", "14.10.1.2.3.4", "14.7.8.8.2"}; 
    headers.Sort(new MySorter()); 



class MySorter : IComparer<string> 
    { 
    public int Compare(string x, string y) 
    { 
    IList<string> a = x.Split('.'); 
    IList<string> b = y.Split('.'); 
    int numToCompare = (a.Count < b.Count) ? a.Count : b.Count; 
    for (int i = 0; i < numToCompare; i++) 
    { 
    if (a[i].Equals(b[i])) 
    continue; 
    int numa = Convert.ToInt32(a[i]); 
    int numb = Convert.ToInt32(b[i]); 
    return numa.CompareTo(numb); 
    } 
    return a.Count.CompareTo(b.Count); 
    } 

    } 
1

Sử dụng IComparer hast những bất lợi lớn của việc lặp lại tính toán khá đắt tiền rất thường xuyên, vì vậy tôi nghĩ precalculating một criterium trật tự sẽ là một ý tưởng hay:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ChapterSort 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      String[] chapters=new String[] {"14.1","14.4.2","14.7.8.8.2","14.10","14.2","14.9","14.10.1.2.3.4","14.1.2.3" }; 

      IEnumerable<String> newchapters=chapters.OrderBy(x => new ChapterNumerizer(x,256,8).NumericValue); 

      foreach (String s in newchapters) Console.WriteLine(s); 

     } 
    } 

    public class ChapterNumerizer 
    { 
     private long numval; 

     public long NumericValue {get{return numval;}} 

     public ChapterNumerizer (string chapter,int n, int m) 
     { 
      string[] c = chapter.Split('.'); 
      numval=0; 
      int j=0; 

      foreach (String cc in c) 
      { 
       numval=n*numval+int.Parse(cc); 
       j++; 
      } 
      while (j<m) 
      { 
       numval*=n; 
       j++; 
      } 
     } 
    } 
} 
1

Giải pháp này tổng quát hơn.

public class SequenceComparer<T> : IComparer<IEnumerable<T>> where T : IComparable<T> 
{ 
    public int Compare(IEnumerable<T> x, IEnumerable<T> y) 
    { 
     IEnumerator<T> enx = x.GetEnumerator(); 
     IEnumerator<T> eny = y.GetEnumerator(); 

     do 
     { 
      bool endx = enx.MoveNext(); 
      bool endy = eny.MoveNext(); 

      if (!endx && !endy) 
       return 0; 

      if (!endx) 
       return -1; 

      if (!endy) 
       return 1; 

      var comp = enx.Current.CompareTo(eny.Current); 
      if(comp != 0) 
       return comp; 
     } while (true); 
    } 
} 

Sau đó sử dụng:

var sv = vers.Select(v => new { Key = v, Split = v.Split('.').Select(Int32.Parse) }); 
var ordered = sv.OrderBy(x => x.Split, new SequenceComparer<int>()).Select(x => x.Key); 
1

Là một nhỏ LINQ one-liner:

List<string> chapters= new List<string>() 
{ 
    "14.1", 
    "14.4.2", 
    "14.7.8.8.2", 
    "14.10", 
    "14.2" 
}; 

chapters.OrderBy(c => Regex.Replace(c, "[0-9]+", match => match.Value.PadLeft(10, '0'))); 

độc lập mức nhưng chắc chắn không phải là hiệu suất tốt nhất ...

Tín là sẽ đến https://stackoverflow.com/a/5093939/226278

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