ElektroStudios
ElektroStudios

Reputation: 20474

Bubble Sort a List using LINQ?

I have a List of DirectoryInfo wich contains folder names like these:

80's
90's
2000
2001

The problem is that the "IO.Directory.GetDirectories" function returns the generic Microsoft Sort so my list is sorted as this:

2000
2001
80's
90's

I know the algorithm to Bubble sort (always I see the usage of a FOR and to generate other temporal objects, I don't like any Bubble sort method I've seen) and I hope if a Bubble Sort can be simplified using LINQ or other improved methods but not a For neither creating extra objects in memory.

How I can Bubble Sort the List(Of DirectoryInfo) by their Directory.Name property ? (obviouslly I want to preserve the DirectoryInfo objects, not to return a couple of sorted Strings), also is possibly to bubble sort it without reallocating the list using LINQ extensions?

UPDATE:

If someone need the information this is the function that I'm using to get the DirectoryInfo list:

' Get Folders
Private Function Get_Folders(ByVal directory As String, ByVal recursive As Boolean) As List(Of IO.DirectoryInfo)
    Dim searchOpt As IO.SearchOption = If(recursive, IO.SearchOption.AllDirectories, IO.SearchOption.TopDirectoryOnly)
    Return IO.Directory.GetDirectories(directory, "*", searchOpt).Select(Function(p) New IO.DirectoryInfo(p)).ToList
End Function

UPDATE 2

Following the suggestions on question comments I'm trying to simplify all the code in just few lines using a regex and LINQ extensions treating the folder names as integers to sort them, the problem is it fails because I have some folders who can't be converted to numbers, this is a example folder names:

80's
90's
2000-2006
2007
2008
Classic
B.S.O
Maquetas

My question is If I can exlude the Non-Digits folders when sorting and then append that excluded folders to the sorted "integer" folder names, I ask this just to don't get all the folders two times to generate two different lists to join them.

Also notice the folder name "2000-2006", if I convert the name to integer I wouldn't get the expected result when sorting.

So just how I could Bubble sort the list folder name content treating them as what are?, strings, not numbers.

Public Class Form1

Dim regex As New System.Text.RegularExpressions.Regex("\D")

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Shown

    For Each folder In Get_Folders("E:\Música\Canciones", False) _
                       .OrderBy(Function(x) Convert.ToInt32(regex.Replace(x.Name, "")))

        MsgBox(folder.Name)
        ' Exception here, because a folder named "B.S.O" and other named as "Classic",
        ' obviouslly they can't be converted to Integer :(

    Next

End Sub

' Get Folders
Private Function Get_Folders(ByVal directory As String, ByVal recursive As Boolean) As List(Of IO.DirectoryInfo)
    Dim searchOpt As IO.SearchOption = If(recursive, IO.SearchOption.AllDirectories, IO.SearchOption.TopDirectoryOnly)
    Return IO.Directory.GetDirectories(directory, "*", searchOpt).Select(Function(p) New IO.DirectoryInfo(p)).ToList
End Function

End Class

Upvotes: 0

Views: 1580

Answers (2)

ElektroStudios
ElektroStudios

Reputation: 20474

Little modification of @L.B solution, I hope this helps someone else:

    Public Shared Function CustomSort(list As List(Of IO.DirectoryInfo)) As List(Of IO.DirectoryInfo)

        Dim maxLen As Integer = list.[Select](Function(s) s.Name.Length).Max()

        Return list.[Select](Function(s) New With { _
            Key .OrgStr = s, _
            Key .SortStr = System.Text.RegularExpressions.Regex.Replace(s.Name, "(\d+)|(\D+)", Function(m) m.Value.PadLeft(maxLen, If(Char.IsDigit(m.Value(0)), " "c, Char.MaxValue))) _
        }).OrderBy(Function(x) x.SortStr).[Select](Function(x) x.OrgStr).ToList
    End Function

Upvotes: 1

L.B
L.B

Reputation: 116168

I translated the code in referenced question using Telerik's online converter. It works for your case too.

Public Shared Function CustomSort(list As IEnumerable(Of String)) As IEnumerable(Of String)
    Dim maxLen As Integer = list.[Select](Function(s) s.Length).Max()

    Return list.[Select](Function(s) New With { _
        Key .OrgStr = s, _
        Key .SortStr = System.Text.RegularExpressions.Regex.Replace(s, "(\d+)|(\D+)", Function(m) m.Value.PadLeft(maxLen, If(Char.IsDigit(m.Value(0)), " "c, Char.MaxValue))) _
    }).OrderBy(Function(x) x.SortStr).[Select](Function(x) x.OrgStr)
End Function

Upvotes: 1

Related Questions