2012-01-09 5 views
2

私は文字列のリストを持っています。各文字列は、パターン "{Path} \ UpdateTo {Version} - {Order}"に従います。バージョン別文字列リストの並べ替え

リストをソートして、最も低いバージョン番号が先頭になるように並べ替える必要があります。バージョン番号が同じ複数のファイルがある場合は、オプションのorderパラメータが追加されます。順序が文字列のいずれかに存在する場合は、順序番号を持たない同じバージョン番号の文字列の上に表示されます。例えば

、(アイテムがランダムに並べられ注意)以下のリストを与える:

var files = new List<string>() { 
    @"C:\Migrations\UpdateTo1.2-2", 
    @"C:\Migrations\UpdateTo1.5-2", 
    @"C:\Migrations\UpdateTo1.2", 
    @"C:\Migrations\UpdateTo1.4", 
    @"C:\Migrations\UpdateTo1.1", 
    @"C:\Migrations\UpdateTo1.5", 
    @"C:\Migrations\UpdateTo1.2-1", 
    @"C:\Migrations\UpdateTo1.5-1" 
}; 

を結果は次のようになります。

var files = new List<string>() { 
    @"C:\Migrations\UpdateTo1.1", 
    @"C:\Migrations\UpdateTo1.2-1", 
    @"C:\Migrations\UpdateTo1.2-2", 
    @"C:\Migrations\UpdateTo1.2", 
    @"C:\Migrations\UpdateTo1.4", 
    @"C:\Migrations\UpdateTo1.5-1", 
    @"C:\Migrations\UpdateTo1.5-2", 
    @"C:\Migrations\UpdateTo1.5" 
} 

私はアイデアのすべての種類にしようとしてきたが、これまでの私の試みは完全な混乱でした。誰かが助けてくれたら、私はそれを感謝します。おかげ

+2

をあなたが試したものの例を与えることができますか? –

+0

あなたのバージョンが9、.9以上にならない限り、アルファベット順のソートを使うこともできます。そうしないと、単純なコンパイラを書く必要があります。 – dtech

+0

パスが混在していると思われますか? –

答えて

5

一時的なクラスを使用して、解析と比較を処理して目的の出力を得ました。私は、あなたがそれをどのように要求したかをすべて取得するコードを含んでいますが、導入された "一時的な"クラスは、単にパス(?)よりも貴重な価値があります。

使用法:

var sorted = files.Select(f => new UpdateTo(f)) 
    .OrderBy(u => u) 
    .Select(u => u.Path) 
    .ToArray(); 

コード:

class UpdateTo : IComparable<UpdateTo> 
{ 
    public decimal Version { get; private set; } 
    public int Order { get; private set; } 
    public string Path { get; private set; } 

    private const string Prefix = "UpdateTo"; 

    public UpdateTo(string path) 
    { 
     /* No error-checking here -- BEWARE!! */ 
     Path = path; 

     string toParse = Path.Substring(Path.IndexOf(Prefix, StringComparison.InvariantCultureIgnoreCase) + Prefix.Length); 
     var split = toParse.Split('-'); 

     Version = decimal.Parse(split[0]); 
     Order = split.Length == 2 ? int.Parse(split[1]) : int.MaxValue; 
    } 

    public int CompareTo(UpdateTo other) 
    { 
     int versionCompare = Version.CompareTo(other.Version); 
     return versionCompare == 0 ? Order.CompareTo(other.Order) : versionCompare; 
    } 
} 

とテスト...ここ

[Test] 
public void ListSort() 
{ 
    const string first = @"C:\Migrations\UpdateTo1.1"; 
    const string second = @"C:\Migrations\UpdateTo1.2-1"; 
    const string third = @"C:\Migrations\UpdateTo1.2-2"; 
    const string fourth = @"C:\Migrations\UpdateTo1.2"; 
    const string fifth = @"C:\Migrations\UpdateTo1.4"; 
    const string sixth = @"C:\Migrations\UpdateTo1.5-1"; 
    const string seventh = @"C:\Migrations\UpdateTo1.5-2"; 
    const string eighth = @"C:\Migrations\UpdateTo1.5"; 

    var files = new List<string>{third, seventh, fourth, fifth, first, eighth, second, sixth}; 

    var sorted = files.Select(f => new UpdateTo(f)) 
     .OrderBy(u => u) 
     .Select(u => u.Path) 
     .ToArray(); 

    Assert.AreEqual(first, sorted[0]); 
    Assert.AreEqual(second, sorted[1]); 
    Assert.AreEqual(third, sorted[2]); 
    Assert.AreEqual(fourth, sorted[3]); 
    Assert.AreEqual(fifth, sorted[4]); 
    Assert.AreEqual(sixth, sorted[5]); 
    Assert.AreEqual(seventh, sorted[6]); 
    Assert.AreEqual(eighth, sorted[7]); 
} 
+0

あなたの答えをありがとう。それは私が一番好きなものでした。私はそれに従うことが簡単だったので、私は似たような試みをしましたが、悲惨に笑ってしまいました。 – nfplee

3
files.Sort(delegate(string str1, string str2) 
{ 
    var pattern = @"(?<version>\d.*?$)"; 
    var version1 = System.Text.RegularExpressions.Regex.Match(str1, pattern).Groups["version"].Value; 
    var version2 = System.Text.RegularExpressions.Regex.Match(str2, pattern).Groups["version"].Value; 

    // TODO: Implement your version comparison logic here 
    return string.Compare(version1, version2); 
}); 

更新

サンプル比較ロジックimplementationは次のようになります。

files.Sort(delegate(string str1, string str2) 
{ 
    var pattern = @"(?<version>\d.*?$)"; 
    var version1 = System.Text.RegularExpressions.Regex.Match(str1, pattern).Groups["version"].Value; 
    var version2 = System.Text.RegularExpressions.Regex.Match(str2, pattern).Groups["version"].Value; 

    if (version1 == version2) return 0; 

    // version1 != version2 

    var major1 = float.Parse(version1.Split('-')[0]); 
    var major2 = float.Parse(version2.Split('-')[0]); 

    if (major1 > major2) return 1; // version1 > version2 
    if (major1 < major2) return -1; // version1 < version2 

    // major1 = major2 

    if (version1.Split('-').Length > version2.Split('-').Length) return -1; 
    if (version1.Split('-').Length < version2.Split('-').Length) return 1; 

    var minor1 = float.Parse(version1.Split('-')[1]); 
    var minor2 = float.Parse(version2.Split('-')[1]); 

    return Comparer<float>.Default.Compare(minor1, minor2); 
}); 
+0

あなたの答えをありがとう。しかし、私はLINQのアプローチが好きだったので、私はオースティンの答えを受け入れてくれました。 – nfplee

1

あなたが次のことを試みることができる:

// Warning! To keep this code clean I 
// left out all error handling. Use at own risk. 
// 
// requires using System.Linq; 
private int VersionSortingValue(string s) 
{ 
    int res = 0; 
    string[] items = s.Split('.', '-'); 
    if(items.Length != 3) 
    { 
     res = 1; 
    } 

    return (int.Parse(items[0]) << 1) + res; 
} 

// actual sorting: 
var prefix = "UpdateTo"; 

Func<string, string> getVersion = 
    x => x.Substring(x.LastIndexOf(prefix) + prefix.Length); 

files = files 
    .OrderBy(x => VersionSortingValue(getVersion(x)) 
    .ThenBy(x => getVersion(x)) 
    .ToList(); 

バージョン番号が大きくなる場合は、natural sortの使用を検討する必要があります。

+0

目的のリストの2番目の項目とこの出力の違いに注意してください。 –

+0

うん。改良されたバージョンでこれを処理できるはずです。 – Nuffin

+0

まだありません。常に{Order}で注文してください。私はすでにオースティンの答えを受け入れたが、とにかく感謝する。 – nfplee

1

は、使用して別の(ややterser、多分読みにくく)バージョンですLINQ:

int prefixLength = "UpdateTo".Length; 

var sorted = from file in files 
      let fileName = System.IO.Path.GetFileName(file) 
      let versionString = fileName.Substring(prefixLength, fileName.Length - prefixLength).Replace('-', '.') 
      let version = new Version(versionString) 
      orderby version 
      select file; 

更新: 以下の洗練されたバージョンは、アカウントに順序値に関する特別なケースを取ります

var sorted = from file in files 
      let fileName = System.IO.Path.GetFileName(file) 
      let versionString = fileName.Substring(prefixLength, fileName.Length - prefixLength).Replace('-', '.') 
      let modified = versionString.IndexOf('.') == versionString.LastIndexOf('.') ? versionString + "." + Int32.MaxValue.ToString() : versionString 
      let version = new Version(modified) 
      orderby version 
      select file; 
+0

あなたの答えをありがとうが、注文パラメータを処理しません。しかし、ハイフンを10進数に変更するのはいい考えです。注文パラメータがない場合は、本当に高い最後の数値を追加することができます。 – nfplee

+0

申し訳ありません。私は注文番号を慎重に十分に読んでいなかった。 – afrischke

+0

既存のSystem.Versionクラス@afrischkeを使用して並べ替えるのがいいアイデアは、私が持っていた同様の問題で本当に助けになりました! – pwhe23

関連する問題