Can't get the name of directories sorted by name

StewartBW 1,145 Reputation points
2024-07-27T23:03:39.8733333+00:00

Hello experts,

I need to get the name of directories sorted by name, just like what is shown in the Windows explorer.

3 folders are in a path, Windows show them in the below order:

0_35_33

7_07_10

18_16_40

But Directory.GetDirectories and DirectoryInfo.GetDirectories both will return in the below order:

0_35_33

18_16_40

7_07_10

Note that the below lines will not help either:

.OrderByDescending(Function(p) p.Name).ToArray()

.OrderByDescending(Function(p) p.CreationTime).ToArray()

Please help :(

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,011 questions
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,737 questions
0 comments No comments
{count} votes

Accepted answer
  1. Jiachen Li-MSFT 32,376 Reputation points Microsoft Vendor
    2024-07-29T01:35:22.82+00:00

    Hi @StewartBW ,

    You can use a lambda expression or a custom sorting logic inline.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim pathname As String = "testfolders"
            Dim directories As String() = Directory.GetDirectories(pathname)
    
            Array.Sort(directories, AddressOf CompareNaturally)
    
            For Each dir As String In directories
                Debug.WriteLine(Path.GetFileName(dir))
            Next
        End Sub
    
        Private Function CompareNaturally(x As String, y As String) As Integer
            Dim xName As String = Path.GetFileName(x)
            Dim yName As String = Path.GetFileName(y)
            Dim xParts As String() = Regex.Split(xName, "(\d+)")
            Dim yParts As String() = Regex.Split(yName, "(\d+)")
    
            For i As Integer = 0 To Math.Min(xParts.Length, yParts.Length) - 1
                If xParts(i) <> yParts(i) Then
                    Dim xPart As Integer
                    Dim yPart As Integer
    
                    If Integer.TryParse(xParts(i), xPart) AndAlso Integer.TryParse(yParts(i), yPart) Then
                        Return xPart.CompareTo(yPart)
                    Else
                        Return xParts(i).CompareTo(yParts(i))
                    End If
                End If
            Next
    
            Return xParts.Length.CompareTo(yParts.Length)
        End Function
    
    

    Best Regards.

    Jiachen Li


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. Castorix31 85,881 Reputation points
    2024-07-27T23:21:37.67+00:00

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  3. Karen Payne MVP 35,436 Reputation points
    2024-07-31T10:16:51.0466667+00:00

    The following will sort properly.

    using System.Text.RegularExpressions;
    
    public static partial class Extensions
    {
        public static IEnumerable<T> NaturalOrderBy<T>(this IEnumerable<T> items, Func<T, string> selector, StringComparer stringComparer = null)
        {
            var regex = new Regex(@"\d+", RegexOptions.Compiled);
    
            int maxDigits = items
                .SelectMany(value => regex.Matches(selector(value))
                    .Select(digitChunk => (int?)digitChunk.Value.Length)).Max() ?? 0;
    
            return items.OrderBy(value => regex.Replace(selector(value), 
                match => match.Value.PadLeft(maxDigits, '0')), 
                stringComparer ?? StringComparer.CurrentCulture);
        }
    }
    

    Example which in this case uses file under a folder of the executable.

    var fileNames = Directory.EnumerateFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Files"), "*.*", new EnumerationOptions
    {
        IgnoreInaccessible = true
    }).ToArray();
    
    List<string> sorted = fileNames.NaturalOrderBy(x => x).ToList();
    sorted.ForEach(x=> Console.WriteLine(Path.GetFileName(x)));
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.