Отсортировать путь к каталогу по алфавиту

#vb.net #sorting

#vb.net #сортировка

Вопрос:

Приведенный ниже код используется для сортировки каталогов в vb.net .

 Dim a As New List(Of String)
            a.Add("abc")
            a.Add("abcd")
            a.Add("abc d")
            a.Add("abc de")
            a.Add("abcdf")

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

Результат:

         abc
        abc d
        abc de
        abcd
        abcdf
        
        
  

В результирующем списке каталоги с пробелом помещаются перед «».

Существует более 1500000 подкаталогов и файлов, на сортировку которых уходит около 50 секунд (метод по умолчанию). Все другие методы, которые мы пробовали, занимают не менее 400 секунд.

как отсортировать путь к каталогу по алфавиту? Есть ли какой-либо встроенный метод для учета обратной косой черты перед пробелом?

Ответ №1:

Вам нужно разбить путь на отдельные названия папок и сравнивать каждое из них по очереди, пока не найдете разницу. Если разницы нет, то вы используете длину для различения, т. Е. папка более высокого уровня идет первой.

 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)
  

Для наглядности вот класс, который инкапсулирует эту функциональность:

 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
  

Его можно использовать, практически не внося изменений в ваш код:

 Dim a As New List(Of FileSystemPath)
a.Add(New FileSystemPath("abc"))
a.Add(New FileSystemPath("abcd"))
a.Add(New FileSystemPath("abc d"))
a.Add(New FileSystemPath("abc de"))
a.Add(New FileSystemPath("abcdf"))

a.Sort()

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

Комментарии:

1. Во-первых, как это может быть в 10 раз медленнее, чем не делать этого вообще? Во-вторых, как насчет того, чтобы в будущем не тратить время людей и фактически информировать их, если вы сделали что-то, что работает, но не соответствует вашим требованиям к производительности? Вам не нужно говорить, что вам нужно опубликовать то, что вы уже сделали. Я почти собирался заставить вас приложить усилия, но потом подумал, что окажу вам услугу, а теперь оказывается, что вы зря потратили мое время. Я больше не повторю эту ошибку.

2. Тем не менее, часть проблемы будет заключаться в том, что первый фрагмент кода разделяет оба пути при каждом сравнении. Я на самом деле не принимал это во внимание, но второй вариант в ответе, т. е. FileSystemPath класс, разделяет каждый путь только один раз, поэтому он должен быть заметно быстрее.

3. Спасибо, мы постараемся сообщить.