views:

119

answers:

2

Hi there, I would like to sort a list of strings which represent paths. The sort result will do have a hierarchical order.

What I mean is: for each directory path, I want to list all files in that path (alphabeticaly or not doesn't matter) in first time. Then, each subdirectory path will be listed. For each subdirectory, I want all files... and so on.

Here is an example:

(Before)

emule/changelog.txt
emule/config/
emule/config/adresses.dat
emule/config/nodes.dat
emule/config/webservices.dat
emule/eMule.tmpl
emule/eMule_Chicane.tmpl
emule/license.txt
emule/license-GER.txt
emule/readme.txt
emule/Skin/
emule/Skin/Daan-V2-8.eMuleSkin.ini
emule/Skin/DaanV2-8/
emule/Skin/DaanV2-8/back.ICO
emule/Skin/DaanV2-8/WebServer.ico
emule/Template.eMuleSkin.ini
emule/webserver/
emule/webserver/add_server.gif
emule/webserver/arrow_down.gif
emule/webserver/arrow_right.gif
emule/webserver/yellow.gif
emule/emule.exe

(After)

emule/changelog.txt
emule/emule.exe
emule/eMule.tmpl
emule/eMule_Chicane.tmpl
emule/license.txt
emule/license-GER.txt
emule/readme.txt
emule/Template.eMuleSkin.ini
emule/config/
emule/config/adresses.dat
emule/config/nodes.dat
emule/config/webservices.dat
emule/Skin/
emule/Skin/Daan-V2-8.eMuleSkin.ini
emule/Skin/DaanV2-8/
emule/Skin/DaanV2-8/back.ICO
emule/Skin/DaanV2-8/WebServer.ico
emule/webserver/
emule/webserver/add_server.gif
emule/webserver/arrow_down.gif
emule/webserver/arrow_right.gif
emule/webserver/yellow.gif

I tried many solutions like Array.Sort() with a custom IComparable function.

Do you have any idea? Thanks so much.

EDIT: here is my IComparable method

zipEntries.Sort(AddressOf compareZipEntryFilenames)

Private Function compareZipEntryFilenames(ByVal x As Object, ByVal y As Object) As Integer
        Dim one As String = CType(x, ZipEntry).FileName
        Dim two As String = CType(y, ZipEntry).FileName

        If Path.GetDirectoryName(one) = Path.GetDirectoryName(two) Then
            Return String.Compare(one, two)
        Else
           Select Regex.Matches(one, "/").Count.CompareTo(Regex.Matches(two, "/").Count)
                Case -1 'one has less / than two; so one then two
                    Return -1
                Case 1 'one has more / than two; so two then one
                    Return 1
                Case Else ' = 0, same number of /; so alphabetical sorting
                    Return String.Compare(one, two)
            End Select
        End If
    End Function
A: 

Insert the below into the class in which the sort occurs, and then use zipEntries.Sort(new PathComparer)

private class PathComparer
        implements IComparer

     Public Function compareZipEntryFilenames(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
        Dim one As String = CType(x, ZipEntry).FileName
        Dim two As String = CType(y, ZipEntry).FileName

        If Path.GetDirectoryName(one) = Path.GetDirectoryName(two) Then
            Return String.Compare(one, two)
        Else
           Select Regex.Matches(one, "/").Count.CompareTo(Regex.Matches(two, "/").Count)
                Case -1 'one has less / than two; so one then two
                    Return -1
                Case 1 'one has more / than two; so two then one
                    Return 1
                Case Else ' = 0, same number of /; so alphabetical sorting
                    Return String.Compare(one, two)
            End Select
        End If
      End Function      
    end class
Will A
This is another way to link IComparable to the Sort() method. Because I don't want to add a class, I decided to create a function in my project class. The behavior is the same.
Neat - I'd not yet encountered the Comparison(Of T) variant of Sort!
Will A
A: 

Turns out to be as simple as:

Private Function compareZipEntryFilenames(ByVal x As ZipEntry, ByVal y As ZipEntry) As Integer

    Dim res As Integer = String.Compare(Path.GetDirectoryName(x.FileName), Path.GetDirectoryName(y.FileName))

    If res = 0 Then
        Return String.Compare(x.FileName, y.FileName)
    Else
        Return res
    End If

End Function
GSerg
Yeah! You are great - you just resolved my problem! Thank you very much
BTW there is a thing I don't understand. Path.PathSeparator returns ";"c -- I think you used it to count "/", not ";". And so, there is never ";" in strings.
Ouch. It works only because it has a bug. And fixing the bug breaks it. Great. I'll post the fixed version.
GSerg
It's what I tried. Strange behavior, isn't it.
I think `Uri.Compare` uses `String.Compare` for a reason... And the reason is that the slash is less than any letter. Try this version.
GSerg
With clear ideas we got clear code. Comparing DirectoryName and then FileName is the simplest approach. Why... why I don't think this way before?!Your solution is perfect.