Повышение производительности при поиске совпадений в большом списке / массиве - PullRequest
0 голосов
/ 28 мая 2020

Я создаю инструмент для поиска изображений в большой папке изображений (400k изображений). В этой папке у меня есть такие изображения:

c: \ images \ 100001_01.jpg c: \ images \ 100001_05.jpg c: \ images \ 100001_07.jpg c: \ images \ 100005_05.jpg c: \ images \ 100010_00.jpg

Тогда у меня есть ссылки в текстовом поле, но только 6 di git номер: 100001 100005 100006 Et c

Итак, у меня есть 1000 ссылок, для которых мне нужны изображения, я хочу l oop через всю папку с изображениями и взять файл, если он существует. Я построил это, используя как массив с циклами, так и список, и получил индекс. Я думал, что получить индекс списка будет намного быстрее, но на самом деле они одинаковы.

Вот две процедуры, которые я разработал, одна использует список, а затем получает FindIndex для получения индекса. Второй вариант - это перебрать все ссылки и в то же время перебрать все изображения, чтобы проверить, содержат ли они эту ссылку - это 400 миллионов циклов, если я использую набор из 1000 ссылок!

Использование списка требует 69 секунд, однако цикл по массивам занимает 64 секунды. Тем не менее создание всех изображений в каталоге с помощью GetFile уже занимает 120 секунд.

Можете ли вы придумать способ сделать это быстрее?

 Private Sub ExtractImagesUsingList()

    Dim ListOfReferences As New List(Of String) 'the actual list of references is in a textbox, ie.: 100001, 100002, etc

    For Each line In txtBox.Lines
        ListOfReferences.Add(line.ToString)
    Next

    Dim ListOfimages As New List(Of String)

    For Each file In IO.Directory.GetFiles("c:\images\")
        ListOfimages.Add(file)
    Next

    For Each ref In ListOfReferences
        Dim index As Integer = ListOfimages.FindIndex(Function(x As String) x.Contains(ref))
    Next
End Sub

Private Sub ExtractImagesUsingArrayLoop()

    Dim ListOfreferences As New List(Of String)'the actual list of references is in a textbox

    For Each line In txtBox.Lines
        If line.Length > 1 Then
            ListOfReferences.Add(line.ToString)
        End If
    Next

    Dim ArrayImages() As String = IO.Directory.GetFiles("c:\images\")

    For Each reference In ListOfReferences
        For Each image In ArrayImages
            If image.Contains(reference) Then
                 Exit For ' I exist the FOR here because I am only interested in one image per reference
            End If
        Next
    Next
End Sub

1 Ответ

0 голосов
/ 28 мая 2020

Не на 100% понятно, что вы пытаетесь достичь sh, но вы можете улучшить производительность, реализовав Directory.EnumerateFiles.

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

Наконец, если каталог изображений не подвергается частым изменений, вы можете кэшировать изображения в словаре, чтобы ускорить поиск в будущем.

Вот примерный пример этих идей. Примечание. Я удалил все ссылки на элементы управления формы и предполагаю, что вместо этого передаются параметры.

Private _imageMap As Dictionary(Of String, ICollection(Of String))

Public ReadOnly Property ImageMap As Dictionary(Of String, ICollection(Of String))
    Get
        If _imageMap Is Nothing Then
            _imageMap = New Dictionary(Of String, ICollection(Of String))()
        End If

        Return _imageMap
    End Get
End Property

Public Sub RefreshImageMap()
    _imageMap = Nothing
End Sub

Public Function GetImagePaths(imageFolder As String, referenceKey As String) As ICollection(Of String)

    Dim imagePaths As ICollection(Of String) = Nothing
    If Not ImageMap.TryGetValue(referenceKey, imagePaths) Then

        imagePaths = Directory.EnumerateFiles(imageFolder, $"{referenceKey}_*.jpg").ToList()
        ImageMap.Add(referenceKey, imagePaths)

    End If

    Return imagePaths

End Function

Также, если вы хотите запустить несколько ссылочных ключей через функцию, но также необходимо сохранить исходную ссылку key, вы можете добавить что-то вроде этого:

Public Iterator Function GetImagePaths(imageFolder As String, referenceKeys As IEnumerable(Of String)) As IEnumerable(Of KeyValuePair(Of String, ICollection(Of String)))

    For Each referenceKey As String In referenceKeys

        Dim imagePaths = GetImagePaths(imageFolder, referenceKey)
        Yield New KeyValuePair(Of String, ICollection(Of String))(referenceKey, imagePaths)
    Next

End Function

Ничего из этого не проверено, и в нем отсутствуют надлежащие проверки параметров функций, но это должно дать вам направление, чтобы попробовать.

...