0

次のフォルダーがあるとします。

New Folder
- New Folder
- New Folder (2)
- New Folder (3)
- New Folder (4)
New Folder (2)
New Folder (3)
New Folder (4)

そしてクエリ

from s in Directory.GetDirectories(@"D:\Project\uploads", "*.*", SearchOption.AllDirectories)
select s

結果:

D:\Project\uploads\New Folder
D:\Project\uploads\New Folder (2)
D:\Project\uploads\New Folder (3)
D:\Project\uploads\New Folder (4)
D:\Project\uploads\New Folder\New Folder
D:\Project\uploads\New Folder\New Folder (2)
D:\Project\uploads\New Folder\New Folder (3)
D:\Project\uploads\New Folder\New Folder (4)

リストを正しい順序でソートする方法はありますか? 私はそれが次のようになると予想しました:

D:\Project\uploads\New Folder
D:\Project\uploads\New Folder\New Folder
D:\Project\uploads\New Folder\New Folder (2)
D:\Project\uploads\New Folder\New Folder (3)
D:\Project\uploads\New Folder\New Folder (4)
D:\Project\uploads\New Folder (2)
D:\Project\uploads\New Folder (3)
D:\Project\uploads\New Folder (4)

どんな助けでも大歓迎です!

4

5 に答える 5

1

これは私が思っていたほど些細なことではありませんでした。おそらく最も健全な解決策は (リストを再帰的に構築する以外に)、ソートを行うための比較子を実装することです。

クラス DirectorySorter : IComparer<文字列>
{
    public int Compare(文字列 x, 文字列 y)
    {
        return StringComparer.Ordinal.Compare(x.Replace(Path.DirectorySeparatorChar, '\0'),
                                        y.Replace(Path.DirectorySeparatorChar, '\0'));
        var xPaths = x.Split(Path.DirectorySeparatorChar);
        var yPaths = y.Split(Path.DirectorySeparatorChar);
        var minLength = Math.Min(xPaths.Length, yPaths.Length);
        for (int i = 0; i < minLength; i++)
        {
            var ires = xPaths[i].CompareTo(yPaths[i]);
            if (ires != 0) return ires;
        }
        var lres = xPaths.Length.CompareTo(yPaths.Length);
        もし (lres == 0)
        {
            lres を返します。
        }
        それ以外の場合 (lres < 0)
        {
            var i = y.LastIndexOf(Path.DirectorySeparatorChar);
            x.Length == i を返しますか? lres : -lres;
        }
        else //if (lres > 0)
        {
            var i = x.LastIndexOf(Path.DirectorySeparatorChar);
            y.Length == i を返しますか? lres : -lres;
        }
    }
}

(Steckの答えを見ると、私が最初に持っていたものとほぼ同じであることがわかります.Ordinal文字列比較子を使用する必要があっただけです。そのため、その変更を使用して機能することがわかりました。)

一方、ディレクトリ構造のいくつかのプロパティを使用してこのタスクを簡素化し、比較子を実装しないようにすることもできます。

var query = Directory
    .EnumerateDirectories(@"D:\Project\uploads", "*", SearchOption.AllDirectories)
    .OrderBy(name => name.Replace(Path.DirectorySeparatorChar, '\0'), StringComparer.Ordinal);
于 2011-04-15T09:31:28.063 に答える
1
private class Comparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        return StringComparer.Ordinal.Compare(x.Replace(Path.DirectorySeparatorChar, '\0'),
                                                y.Replace(Path.DirectorySeparatorChar, '\0'));
    }
}

その後

var source = Directory.GetDirectories(@"D:\Project\uploads", "*.*", SearchOption.AllDirectories)
var target = source.OrderBy(x => x, new Comparer()).ToArray();
于 2011-04-15T10:36:58.963 に答える
0

デフォルトの順序について変更する必要があるのは、\文字が常にアルファベットの最初の文字として扱われるようにすることだけです。これを実装する方法について正確な答えはありませんが、次のとおりです。

  • 文字列を他のすべての文字よりも小さい文字order byに置き換える方法を見つけた場合は、節を使用して、この置き換えられた文字列をキーとして使用できます。\

  • Array.Sort文字列比較を再実装する文字列比較子を使用および実装できますが、\文字に関するこの追加の規則をエンコードします。

于 2011-04-15T09:10:49.980 に答える
0

.NET 4.0 で試す

 Directory.EnumerateDirectories(@"D:\Project\uploads", "*.*", SearchOption.AllDirectories) 

それはあなたが期待することをするかもしれません。そうでない場合は、明示的に行うことができます。

 Directory.GetDirectories(@"D:\Project\uploads")
      .SelectMany(dir => dir.GetDirectories().OrderBy(sub => sub.Name))

最後に、次のようなことをするかもしれません:

 from s in Directory.GetDirectories(@"D:\Project\uploads", "*.*", SearchOption.AllDirectories)
 order by s.Parent.Name, s.Name
 select s

 from s in Directory.GetDirectories(@"D:\Project\uploads", "*.*", SearchOption.AllDirectories)
 let members = s.Name.Split(new [] {Path.SeparatorChar})
 order by members[2], s.Name
 select s

さらに制御/柔軟性を得るために。ニーズに応じて最も簡単なアプローチを選択

于 2011-04-15T09:08:07.797 に答える
0

コメントと回答ありがとうございます。

再帰を使えば人生はずっと楽になると思う

void Main()
{
    string rootFolder = @"D:\Project\uploads";

    string[] f = Directory.GetDirectories(rootFolder, "*.*", SearchOption.AllDirectories);

    Func<string, string[]> build = null;

    build = (p) => {
        return (from x in f where Path.GetDirectoryName(x) == p
                from y in new string[]{ x }.Union(build(x)) select y).ToArray();
    };

    f = build(rootFolder).Dump();
}
于 2011-04-15T09:37:55.277 に答える