Страницы: 1
RSS
Проверка совпадений на множестве листах., Какой алгоритм решения выбрать?
 
Здравствуйте, россиян с прошедшим праздником.
Имеется файл  10 и более листов, по 1000 и более записей на каждом.
Передо мной стоит задача - проверить все записи на повтор, в случаях повтора вывести отдельным списком.
Вижу два варианта:
1. Методом Find ищем каждую запись первого листа на всех листах, начиная со второго; затем каждую запись второго листа, на всех, начиная с третьего, и т.д.
2. Создаю словарь, в Item - словари по листам, и далее как выше.
Так вот сижу, как буриданов осел, и не знаю, какой метод выбрать...
Первый проще в реализации, но не будет ли он "тормознутым"?
Второй посложнее, но даст ли он ощутимый выигрыш в скорости? и даст ли вообще?

зы. файл не прикладываю, т.к. вопрос общего порядка; если считаете необходимым, сварганю пример.
 
Здравствуйте Михаил.
Делал похожую задачу на работе - поиск дублей на разных листах в книге, после долгих мучений остановился на варианте со словарем.
Причина выбора была в скорости обработки данных.
Изменено: Александр Макаров - 05.11.2016 11:36:17
 
Александр Макаров, спасибо, учтем ваше мнение.
Может еще кто выскажется.
 
Доброе время суток.
Пусть значений на листе в среднем N, а листов M. Тогда для операций со словарём вам нужно будет проверить N * M значений в нарастающем словаре. Стоимость поиска в словаре Ln(P), где P число уникальных значений. Пусть все значения уникальны (худший случай), тогда нужно будет выполнить
N * M * Ln(N * M) операций.
Через Find. Для первого листа поисков N * (N / 2) * (M - 1), для второго N * (N / 2) * (M - 2). То есть, подводя итоги, нужно будет выполнить
N * (N / 2) * M * (M - 1 ) / 2 операций. Где N / 2 - средняя оценка нахождения значения в списке длиной N.
Вот и сравните, что будет быстрее ;)
Успехов.
 
Цитата
Михаил С. написал:
Второй посложнее
Да ну?
Код
Sub мяу()
    Dim arr, sh As Worksheet, i&, j&, a
    With CreateObject("Scripting.Dictionary")
        For Each sh In Worksheets
            arr = sh.UsedRange.Value
            For i = LBound(arr) To UBound(arr)
                For j = LBound(arr, 2) To UBound(arr, 2)
                  If Len(arr(i, j)) Then .Item(arr(i, j)) = .Item(arr(i, j)) + 1
                Next
            Next
        Next
        arr = .Keys
        For Each a In arr
            If .Item(a) = 1 Then .Remove (a)
        Next
        Set sh = Worksheets.Add
        sh.Range("A1").Resize(.Count) = Application.Transpose(.Keys)
    End With
End Sub
 
Сделал маленький тест (не знаю насколько корректен), на моем компе словарь более чем в сто раз быстрее Find.
А с учетом варианта Андрея (RAN, ), наверно будет еще быстрее.
 
Миш, а так еще быстрее
Код
Sub мяв()
    Dim arr, sh As Worksheet, i&, j&
    Dim oDik1 As Object, oDik2 As Object
    Set oDik1 = CreateObject("Scripting.Dictionary")
    Set oDik2 = CreateObject("Scripting.Dictionary")
    For Each sh In Worksheets
        arr = sh.UsedRange.Value
        For i = LBound(arr) To UBound(arr)
            For j = LBound(arr, 2) To UBound(arr, 2)
                If Len(arr(i, j)) Then
                    If oDik1.Exists(arr(i, j)) Then
                        oDik2.Item(arr(i, j)) = 1
                    Else
                        oDik1.Item(arr(i, j)) = oDik1.Item(arr(i, j)) + 1
                    End If
                End If
            Next
        Next
    Next
    Set sh = Worksheets.Add
    sh.Range("A1").Resize(oDik2.Count) = Application.Transpose(oDik2.Keys)
End Sub
 
Да, Андрей, спасибо. Скорее всего твой алгоритм возьму в работу.
Страницы: 1
Наверх