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<string>
{
    公共 int 比较(字符串 x,字符串 y)
    {
        返回 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) 返回ires;
        }
        var lres = xPaths.Length.CompareTo(yPaths.Length);
        如果(lres == 0)
        {
            返回 lres;
        }
        否则如果 (lres < 0)
        {
            var i = y.LastIndexOf(Path.DirectorySeparatorChar);
            返回 x.Length == i ?lres:-lres;
        }
        否则 //如果 (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

使用 .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

您唯一需要更改的默认顺序是确保该\字符始终被视为字母表中的第一个字母。我没有确切的答案如何实现这一点,但是:

  • order by如果您找到一种方法\在字符串中替换为小于所有其他字符的字符并使用此替换字符串作为键,则可以使用子句。

  • 您可以使用Array.Sort和实现重新实现字符串比较的字符串比较器,但对有关\字符的附加规则进行编码。

于 2011-04-15T09:10:49.980 回答
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 回答