IT researcher
IT researcher

Reputation: 3304

Sort directory path alphabetically

Below code is used for sorting Directories in vb.net.

Dim a As New List(Of String)
            a.Add("a\b\c")
            a.Add("a\b\c\d")
            a.Add("a\b\c d")
            a.Add("a\b\c d\e")
            a.Add("a\b\c\d\f")

            a.Sort(Function(x, Y) (x).CompareTo((Y)))
        
        

result:

        a\b\c
        a\b\c d
        a\b\c d\e
        a\b\c\d
        a\b\c\d\f
        
        

In the result list directories with space is placed before "\".

There are more than 1500000 sub-directories and files it takes around 50 seconds to sort(default method) all other methods we tried is taking at least 400 seconds.

how to sort directory path alphabetically? Is there any built in method to consider Backslash before space ?

Upvotes: 0

Views: 202

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54417

You need to break the path up into individual folder names and compare each of them in turn until you find a difference. If there is no difference then you use the length to differentiate, i.e. higher-level folder comes first.

a.Sort(Function(x, y)
           Dim xFolderNames As New List(Of String)
           Dim yFolderNames As New List(Of String)

           'Split first path into folder names.
           Do Until String.IsNullOrEmpty(x)
               xFolderNames.Insert(0, Path.GetFileName(x))
               x = Path.GetDirectoryName(x)
           Loop

           'Split second path into folder names.
           Do Until String.IsNullOrEmpty(y)
               yFolderNames.Insert(0, Path.GetFileName(y))
               y = Path.GetDirectoryName(y)
           Loop

           Dim result = 0

           'Compare up to as many folders as are in the shortest path.
           For i = 0 To Math.Min(xFolderNames.Count, yFolderNames.Count) - 1
               result = xFolderNames(i).CompareTo(yFolderNames(i))

               If result <> 0 Then
                   'A difference has been found.
                   Exit For
               End If
           Next

           If result = 0 Then
               'No difference was found so put the shortest path first.
               result = xFolderNames.Count.CompareTo(yFolderNames.Count)
           End If

           Return result
       End Function)

For good measure, here's a class that encapsulates that functionality:

Imports System.Collections.ObjectModel
Imports System.IO

Public Class FileSystemPath
    Implements IComparable, IComparable(Of FileSystemPath)

    Public ReadOnly Property FullPath As String

    Public ReadOnly Property PartialPaths As ReadOnlyCollection(Of String)

    Public Sub New(fileOrFolderPath As String)
        FullPath = fileOrFolderPath

        Dim partialPaths As New List(Of String)

        Do Until String.IsNullOrEmpty(fileOrFolderPath)
            partialPaths.Insert(0, Path.GetFileName(fileOrFolderPath))
            fileOrFolderPath = Path.GetDirectoryName(fileOrFolderPath)
        Loop

        Me.PartialPaths = New ReadOnlyCollection(Of String)(partialPaths)
    End Sub

    Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
        Return CompareTo(DirectCast(obj, FileSystemPath))
    End Function

    Public Function CompareTo(other As FileSystemPath) As Integer Implements IComparable(Of FileSystemPath).CompareTo
        Dim result = 0

        'Compare up to as many folders as are in the shortest path.
        For i = 0 To Math.Min(PartialPaths.Count, other.PartialPaths.Count) - 1
            result = PartialPaths(i).CompareTo(other.PartialPaths(i))

            If result <> 0 Then
                'A difference has been found.
                Exit For
            End If
        Next

        If result = 0 Then
            'No difference was found so put the shortest path first.
            result = PartialPaths.Count.CompareTo(other.PartialPaths.Count)
        End If

        Return result
    End Function


    Public Overrides Function ToString() As String
        Return FullPath
    End Function

End Class

It can be used with barely a change to your code:

Dim a As New List(Of FileSystemPath)
a.Add(New FileSystemPath("a\b\c"))
a.Add(New FileSystemPath("a\b\c\d"))
a.Add(New FileSystemPath("a\b\c d"))
a.Add(New FileSystemPath("a\b\c d\e"))
a.Add(New FileSystemPath("a\b\c\d\f"))

a.Sort()

Console.WriteLine(String.Join(Environment.NewLine, a))
Console.ReadLine()

Upvotes: 1

Related Questions