2012-01-23 5 views
8

私はさまざまな深度の章があります。14.1.2.3と14.10.1.2.3.4のようなチャプターの並べ替え

ですので、14.1と14.4.2と14.7.8.8.2などがあります。

英数字でソートされた14.10は14.2より前に表示されます。それは良くないね。それは14.9の後に来るはずです。

先行ゼロを付けずに、簡単にソートする方法はありますか? f.e. linqと?私は今、この権利をした

+2

私は受け入れられた答え[ここ](http://stackoverflow.com/questions/6248039/how-to-sort-list-of-ip-addresses-using-c-sharp)もあなたのケースで有効だと思います。あなたは4つの "レベル"に制限されますが。 –

+0

はかなり良い、4つのレベル - okと見えます。より多くのアイデアはまだ良いだろう:) – Harry

答えて

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

これは機能します!私はあなたがそれを解決したスタイルが好きです。ありがとう。 – Harry

4

、いくつかのテストを必要とする:

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

私はこのソリューションを最初にテストし、何らかの理由で最大実行時間で終了する膨大な処理を実行しています...あなたの時間は大変ありがとうございます。しかし、私にとっては、神秘的な理由で非常にうまくいきません。 :| – Harry

+0

私はテストを読み込んでいませんでした。好奇心のために、あなたのコレクションには何点ありますか? –

+0

合計約1500個の異なるアイテムがあります: @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

しまうたIComparerのhastのに非常に多くの場合、かなり高価な計算を繰り返すの大きな欠点を使用するので、私は注文クリテリウムを事前に計算思いました

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

この解決策はより一般的です。

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); 
    } 
} 

は、次に使用:小さなLINQワンライナーとして

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

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'))); 

レベルの独立した、しかし確実ではない最高のパフォーマンス...

クレジットがありますhttps://stackoverflow.com/a/5093939/226278

関連する問題