Страницы: 1
RSS
Сравнение таблиц между собой и формирование таблиц полных совпадений
 
Здравствуйте,

в процессе исследования возникла проблема: имеются таблицы с данными (лист2). Одни таблицы могут быть уникальными (содержат хотя бы один элемент, которого нет в другой таблице), а у других - все элементы одинаковые. Для исследования нужны номера таблиц, которые полностью совпадают (оформил результат на листе 3).
Изменено: Сироп Клубничный - 21.04.2021 15:28:35
 
Код
Option Explicit

Sub АргентинаЯмайка()
    Dim dic As Object
    Set dic = GetDic()
        
    If dic.Count > 0 Then
        Dim arr As Variant
        arr = CompareTb(dic)
    End If
    
    Dim rOut As Range
    Set rOut = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    OutArr arr, rOut
End Sub

Sub OutArr(arr As Variant, rOut As Range)
    With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))
        .NumberFormat = "@"
        .Cells = arr
        .EntireColumn.AutoFit
    End With
End Sub

Function CompareTb(dic As Object) As Variant
    Dim arr As Variant
    ReDim arr(1 To 3 * (dic.Count * (dic.Count - 1)), 1 To 3)
    Dim u As Long
    Dim i As Long
    Dim j As Long
    Dim y As Long
    Dim x As Byte
    Dim irr As Variant
    Dim jrr As Variant
    Dim f As Boolean
    For i = 0 To dic.Count - 2
        irr = dic.Items()(i)
        For j = i + 1 To dic.Count - 1
            jrr = dic.Items()(j)
            If UBound(irr, 1) = UBound(jrr, 1) Then
                
                f = True
                For y = 2 To UBound(irr, 1)
                    For x = 1 To UBound(irr, 2)
                        If irr(y, x) <> jrr(y, x) Then
                            f = False
                            Exit For
                        End If
                    Next
                    If Not f Then Exit For
                Next
                If f Then
                    u = u + 3
                    For x = 1 To UBound(irr, 2)
                        arr(u + 0, x) = irr(1, x)
                        arr(u + 1, x) = jrr(1, x)
                    Next
                End If
            End If
        Next
    Next
    CompareTb = arr
End Function


Function GetDic() As Object
    Dim sh As Worksheet
    Set sh = ActiveSheet
    With sh
        Dim y As Long
        Dim arr As Variant
        y = .Cells(.Rows.Count, 1).End(xlUp).Row
        arr = .Range(.Cells(1, 1), .Cells(y + 1, 1))
        
        Dim b As Long
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        For y = 3 To UBound(arr, 1)
            If IsEmpty(arr(y, 1)) Then
                If b > 0 Then
                    dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    b = 0
                End If
            Else
                If Mid(arr(y, 1), 3, 1) = "-" Then
                    If b > 0 Then
                        dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    End If
                    b = y
                End If
            End If
        Next
    End With
    Set GetDic = dic
End Function
 
МатросНаЗебре, все идеально работает. Спасибо Вам большое!

Хотелось бы также научиться. С высшей математикой за несколько лет обучения получилось, а вот в кодинге надо с нуля азов начинать
 
МатросНаЗебре, здравствуйте. Можно у Вас уточнить: имеется ли какое-либо ограничение по количеству строк для данного макроса?

При количестве строк 7151 (325 таблиц) все отлично срабатывает, а при количестве строк 25628 (3080 таблиц) после 1,5 часов возникает ошибка run-time error 1004
Код
With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))

Данная строчка подсвечивается при ошибке run-time error 1004
 
Сироп Клубничный, здравствуйте
Попробуйте Полное (расширенное) сравнение двух списков (столбцов)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Сироп Клубничный написал: 3080 таблиц... после 1,5 часов
При таком времени выполнения и таком количестве... Думать об оптимизации надо.
Ошибка не в VBA, это что-то внешнее (объекты Excel, память...)
 
Код
Option Explicit
 
Sub АргентинаЯмайка()
    Dim dic As Object
    Set dic = GetDic()
         
    If dic.Count > 0 Then
        Dim arr As Variant
        arr = CompareTb(dic)
    End If
     
    Dim rOut As Range
    Set rOut = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    OutArr arr, rOut
End Sub
 
Sub OutArr(arr As Variant, rOut As Range)
    With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))
        .NumberFormat = "@"
        .Cells = arr
        .EntireColumn.AutoFit
    End With
End Sub
 
Function CompareTb(dic As Object) As Variant
    Dim arr As Variant
    ReDim arr(1 To 3 * (dic.Count * (dic.Count - 1)), 1 To 3)
    Dim u As Long
    Dim i As Long
    Dim j As Long
    Dim y As Long
    Dim x As Byte
    Dim irr As Variant
    Dim jrr As Variant
    Dim f As Boolean
    For i = 0 To dic.Count - 2
        irr = dic.Items()(i)
        For j = i + 1 To dic.Count - 1
            jrr = dic.Items()(j)
            If UBound(irr, 1) = UBound(jrr, 1) Then
                 
                f = True
                For y = 2 To UBound(irr, 1)
                    For x = 1 To UBound(irr, 2)
                        If irr(y, x) <> jrr(y, x) Then
                            f = False
                            Exit For
                        End If
                    Next
                    If Not f Then Exit For
                Next
                If f Then
                    u = u + 3
                    For x = 1 To UBound(irr, 2)
                        arr(u + 0, x) = irr(1, x)
                        arr(u + 1, x) = jrr(1, x)
                    Next
                End If
            End If
        Next
    Next
    
    u = u + 1
    If u > Application.Rows.Count Then u = Application.Rows.Count
    
    Dim brr As Variant
    ReDim brr(1 To u, 1 To 3)
    For y = 1 To UBound(brr, 1)
    For x = 1 To 3
        brr(y, x) = arr(y, x)
    Next
    Next
    
    CompareTb = brr
End Function
 
 
Function GetDic() As Object
    Dim sh As Worksheet
    Set sh = ActiveSheet
    With sh
        Dim y As Long
        Dim arr As Variant
        y = .Cells(.Rows.Count, 1).End(xlUp).Row
        arr = .Range(.Cells(1, 1), .Cells(y + 1, 1))
         
        Dim b As Long
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        For y = 3 To UBound(arr, 1)
            If IsEmpty(arr(y, 1)) Then
                If b > 0 Then
                    dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    b = 0
                End If
            Else
                If Mid(arr(y, 1), 3, 1) = "-" Then
                    If b > 0 Then
                        dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    End If
                    b = y
                End If
            End If
        Next
    End With
    Set GetDic = dic
End Function
 
Jack Famous, для текущего исследования не совсем подходит, но вероятно для других задач пригодится. Спасибо

МатросНаЗебре, благодарю за макросы. С большим количеством данных справляется. Если можно поинтересоваться, то в чем отличие второго макроса от первого? Оптимизация алгоритма или что-то другое?
 
Цитата
Сироп Клубничный написал:
Если можно поинтересоваться, то в чем отличие второго макроса от первого?
Во втором варианте уменьшился размер выводимого массива.
В первом варианте количество строк - это условно квадрат от количества элементов. При количестве элементов больше ~1000, размер массива вываливался за размер листа. Возникала ошибка при выводе.
Во втором варианте размер подобран под фактически требуемое значение.
 
МатросНаЗебре, извините, можно ещё уточнить? В макросе происходит процесс сравнивания и далее есть условие, что если блоки равны, то они отбираются на новый рабочий лист. Я хотел спросить, если в строчке заменить "=" на "<>", то будет ли макрос срабатывать как обратная задача, т.е. по выделению уникальных блоков, содержимое которых нет ни в одном другом?

В прилепленном файле я пошел от обратного - через сравнение двух столбцов с отобранными макросом блоками и всех имеющихся. Но при большом количестве затратно конечно получается.  
Изменено: Сироп Клубничный - 13.05.2021 11:54:24
 
Так выведет блоки, содержимое которых отсутствует в других блоках
Код
Option Explicit

Sub АргентинаЯмайка()
    Dim dic As Object
    Set dic = GetDic()
          
    If dic.Count > 0 Then
        Dim ar1 As Variant
        Dim ar2 As Variant
        CompareTb dic, ar1, ar2, True
        CompareTb dic, ar1, ar2, False
        
    End If
      
    Dim rOut As Range
    Set rOut = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    OutArr ar1, rOut
    OutArr ar2, rOut.Cells(1, 5)
End Sub
  
Sub OutArr(arr As Variant, rOut As Range)
    With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))
        .NumberFormat = "@"
        .Cells = arr
        .EntireColumn.AutoFit
    End With
    rOut.Parent.Parent.Saved = True
End Sub
  
Function CompareTb(dic As Object, ByRef arrIn1 As Variant, ByRef arrIn2 As Variant, compareMod As Boolean) As Boolean
    Dim arr As Variant
    ReDim arr(1 To 3 * (dic.Count * (dic.Count - 1)), 1 To 3)
    
    Dim ar2 As Variant
    ReDim ar2(1 To 3 * (dic.Count * (dic.Count - 1)), 1 To 3)
    
    Dim u As Long
    Dim i As Long
    Dim j As Long
    Dim w As Long
    Dim y As Long
    Dim x As Byte
    Dim irr As Variant
    Dim jrr As Variant
    Dim f As Boolean
    Dim atLeastOne As Boolean
    For i = 0 To dic.Count - 2
        irr = dic.Items()(i)
        atLeastOne = False
        For j = IIf(compareMod, i + 1, 0) To dic.Count - 1
            If i <> j Then
                jrr = dic.Items()(j)
                If UBound(irr, 1) = UBound(jrr, 1) Then
                      
                    f = True
                    For y = 2 To UBound(irr, 1)
                        For x = 1 To UBound(irr, 2)
                            If irr(y, x) <> jrr(y, x) Then
                                f = False
                                Exit For
                            End If
                        Next
                        If Not f Then Exit For
                    Next
                    If f Then
                        u = u + 3
                        For x = 1 To UBound(irr, 2)
                            arr(u + 0, x) = irr(1, x)
                            arr(u + 1, x) = jrr(1, x)
                        Next
                        atLeastOne = True
                    End If
                End If
            End If
        Next
        If atLeastOne = False Then
            w = w + 3
            For x = 1 To UBound(irr, 2)
                ar2(w, x) = irr(1, x)
            Next
        End If
    Next
     
    If compareMod Then
        u = u + 1
        If u > Application.Rows.Count Then u = Application.Rows.Count
         
        Dim brr As Variant
        ReDim brr(1 To u, 1 To 3)
        For y = 1 To UBound(brr, 1)
        For x = 1 To 3
            brr(y, x) = arr(y, x)
        Next
        Next
         
        arrIn1 = brr
    Else
        w = w + 1
        If w > Application.Rows.Count Then w = Application.Rows.Count
         
         
        ReDim brr(1 To w, 1 To 3)
        For y = 1 To UBound(brr, 1)
        For x = 1 To 3
            brr(y, x) = ar2(y, x)
        Next
        Next
        
        arrIn2 = brr
    End If
     
    CompareTb = True
End Function
  
  
Function GetDic() As Object
    Dim sh As Worksheet
    Set sh = ActiveSheet
    With sh
        Dim y As Long
        Dim arr As Variant
        y = .Cells(.Rows.Count, 1).End(xlUp).Row
        arr = .Range(.Cells(1, 1), .Cells(y + 1, 1))
          
        Dim b As Long
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        For y = 3 To UBound(arr, 1)
            If IsEmpty(arr(y, 1)) Then
                If b > 0 Then
                    dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    b = 0
                End If
            Else
                If Mid(arr(y, 1), 3, 1) = "-" Then
                    If b > 0 Then
                        dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    End If
                    b = y
                End If
            End If
        Next
    End With
    Set GetDic = dic
End Function

 
Пробовал на разных компьютерах - на больших объёмах все-таки не хочет работать)  RunTime Error 7 - Out of Memory выдаёт на двух ПК (8 и 16 гб оперативной с минимумом программ)
Подсвечивает строку 32:
Код
ReDim arr(1 To 3 * (dic.Count * (dic.Count - 1)), 1 To 3)
А на ноутбуке(16 гб оперативной) запускается, пока не отвечает  :D
В любом случае, МатросНаЗебре, огромнейшая благодарность вам за помощь в исследовании и экономии времени
Изменено: Сироп Клубничный - 17.05.2021 17:00:38
 
Сироп Клубничный, можно ускорить в разы (может, в десятки или даже сотни раз с таким временем как у вас), но на до думать и это не бесплатно
Если интересно, пишите
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Так не будет возникать ошибка в указанной строке.
Код
Option Explicit
 
Sub АргентинаЯмайка()
    Dim dic As Object
    Set dic = GetDic()
           
    If dic.Count > 0 Then
        Dim ar1 As Variant
        Dim ar2 As Variant
        CompareTb dic, ar1, ar2, True
        CompareTb dic, ar1, ar2, False
         
    End If
       
    Dim rOut As Range
    Set rOut = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    OutArr ar1, rOut
    OutArr ar2, rOut.Cells(1, 5)
End Sub
   
Sub OutArr(arr As Variant, rOut As Range)
    With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))
        .NumberFormat = "@"
        .Cells = arr
        .EntireColumn.AutoFit
    End With
    rOut.Parent.Parent.Saved = True
End Sub
   
Function CompareTb(dic As Object, ByRef arrIn1 As Variant, ByRef arrIn2 As Variant, compareMod As Boolean) As Boolean
    Dim arr As Variant
    'ReDim arr(1 To 3 * (dic.Count * (dic.Count - 1)), 1 To 3)
     ReDim arr(1 To 2, 1 To 3)
     
    Dim ar2 As Variant
    'ReDim ar2(1 To 3 * (dic.Count * (dic.Count - 1)), 1 To 3)
     ReDim ar2(1 To 1, 1 To 3)
     
    Dim col1 As New Collection
    Dim col2 As New Collection
     
    Dim u As Long
    Dim i As Long
    Dim j As Long
    Dim w As Long
    Dim y As Long
    Dim x As Byte
    Dim irr As Variant
    Dim jrr As Variant
    Dim f As Boolean
    Dim atLeastOne As Boolean
    For i = 0 To dic.Count - 2
        irr = dic.Items()(i)
        atLeastOne = False
        For j = IIf(compareMod, i + 1, 0) To dic.Count - 1
            If i <> j Then
                jrr = dic.Items()(j)
                If UBound(irr, 1) = UBound(jrr, 1) Then
                       
                    f = True
                    For y = 2 To UBound(irr, 1)
                        For x = 1 To UBound(irr, 2)
                            If irr(y, x) <> jrr(y, x) Then
                                f = False
                                Exit For
                            End If
                        Next
                        If Not f Then Exit For
                    Next
                    If f Then
                        u = u + 3
                        For x = 1 To UBound(irr, 2)
                            'arr(u + 0, x) = irr(1, x)
                            'arr(u + 1, x) = jrr(1, x)
                            arr(1, x) = irr(1, x)
                            arr(2, x) = jrr(1, x)
                        Next
                        col1.Add arr
                        atLeastOne = True
                    End If
                End If
            End If
        Next
        If atLeastOne = False Then
            w = w + 3
            For x = 1 To UBound(irr, 2)
                'ar2(w, x) = irr(1, x)
                ar2(1, x) = irr(1, x)
            Next
            col2.Add ar2
        End If
    Next
      
    If compareMod Then
        u = u + 1
        If u > Application.Rows.Count Then u = Application.Rows.Count
          
        Dim brr As Variant
        ReDim brr(1 To u, 1 To 3)
'        For y = 1 To UBound(brr, 1)
'        For x = 1 To 3
'            brr(y, x) = arr(y, x)
'        Next
'        Next
        y = 1
        For Each arr In col1
            For x = 1 To 3
                brr(y + 0, x) = arr(1, x)
                brr(y + 1, x) = arr(2, x)
            Next
            y = y + 3
        Next
        
        arrIn1 = brr
    Else
        w = w + 1
        If w > Application.Rows.Count Then w = Application.Rows.Count


        ReDim brr(1 To w, 1 To 3)
'        For y = 1 To UBound(brr, 1)
'        For x = 1 To 3
'            brr(y, x) = ar2(y, x)
'        Next
'        Next
        y = 1
        For Each arr In col2
            For x = 1 To 3
                brr(y, x) = arr(1, x)
            Next
            y = y + 2
        Next

        arrIn2 = brr
    End If
      
    CompareTb = True
End Function
   
   
Function GetDic() As Object
    Dim sh As Worksheet
    Set sh = ActiveSheet
    With sh
        Dim y As Long
        Dim arr As Variant
        y = .Cells(.Rows.Count, 1).End(xlUp).Row
        arr = .Range(.Cells(1, 1), .Cells(y + 1, 1))
           
        Dim b As Long
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        For y = 3 To UBound(arr, 1)
            If IsEmpty(arr(y, 1)) Then
                If b > 0 Then
                    dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    b = 0
                End If
            Else
                If Mid(arr(y, 1), 3, 1) = "-" Then
                    If b > 0 Then
                        dic.Item(dic.Count) = .Range(.Cells(b, 1), .Cells(y - 1, 3))
                    End If
                    b = y
                End If
            End If
        Next
    End With
    Set GetDic = dic
End Function
Изменено: МатросНаЗебре - 18.05.2021 11:58:46
 
А так будет быстрее.
Код
Option Explicit
 
Sub АргентинаБразилия()
    Dim dt As Date: dt = Now

    Dim dic As Object
    Set dic = GetDic()
           
    If dic.Count > 0 Then
        Dim ar1 As Variant
        Dim ar2 As Variant
        CompareTb dic, ar1, ar2, True
        CompareTb dic, ar1, ar2, False
    End If
       
    Dim rOut As Range
    Set rOut = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    OutArr ar1, rOut
    OutArr ar2, rOut.Cells(1, 5)
    
    Debug.Print Format(Now - dt, "nn:ss") & " строка"
End Sub
   
Private Sub OutArr(arr As Variant, rOut As Range)
    With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))
        .NumberFormat = "@"
        .Cells = arr
        .EntireColumn.AutoFit
    End With
    rOut.Parent.Parent.Saved = True
End Sub
   
Private Function CompareTb(dic As Object, ByRef arrIn1 As Variant, ByRef arrIn2 As Variant, compareMod As Boolean) As Boolean
    Dim arr As Variant
     ReDim arr(1 To 2, 1 To 3)
     
    Dim ar2 As Variant
     ReDim ar2(1 To 1, 1 To 3)
     
    Dim col1 As New Collection
    Dim col2 As New Collection
     
    Dim u As Long
    Dim i As Long
    Dim j As Long
    Dim w As Long
    Dim y As Long
    Dim x As Byte
    Dim irr As Variant
    Dim jrr As Variant
    Dim f As Boolean
    Dim atLeastOne As Boolean
    For i = 0 To dic.Count - 2
        irr = dic.Items()(i)
        atLeastOne = False
        For j = IIf(compareMod, i + 1, 0) To dic.Count - 1
            If i <> j Then
                jrr = dic.Items()(j)
                If Len(irr(2)) = Len(jrr(2)) Then
                    If irr(2) = jrr(2) Then
                        u = u + 3
                        For x = 1 To UBound(irr(1), 2)
                            arr(1, x) = irr(1)(1, x)
                            arr(2, x) = jrr(1)(1, x)
                        Next
                        col1.Add arr
                        atLeastOne = True
                    End If
                End If
            End If
        Next
        If atLeastOne = False Then
            w = w + 3
            For x = 1 To UBound(irr(1), 2)
                ar2(1, x) = irr(1)(1, x)
            Next
            col2.Add ar2
        End If
    Next
      
    If compareMod Then
        u = u + 1
        If u > Application.Rows.Count Then u = Application.Rows.Count
          
        Dim brr As Variant
        ReDim brr(1 To u, 1 To 3)
        y = 1
        For Each arr In col1
            For x = 1 To 3
                brr(y + 0, x) = arr(1, x)
                brr(y + 1, x) = arr(2, x)
            Next
            y = y + 3
        Next
        
        arrIn1 = brr
    Else
        w = w + 1
        If w > Application.Rows.Count Then w = Application.Rows.Count


        ReDim brr(1 To w, 1 To 3)
        y = 1
        For Each arr In col2
            For x = 1 To 3
                brr(y, x) = arr(1, x)
            Next
            y = y + 2
        Next

        arrIn2 = brr
    End If
      
    CompareTb = True
End Function
   
   
Private Function GetDic() As Object
    Dim sh As Worksheet
    Set sh = ActiveSheet
    With sh
        Dim y As Long
        Dim arr As Variant
        y = .Cells(.Rows.Count, 1).End(xlUp).Row
        arr = .Range(.Cells(1, 1), .Cells(y + 1, 1))
           
        Dim b As Long
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        For y = 3 To UBound(arr, 1)
            If IsEmpty(arr(y, 1)) Then
                If b > 0 Then
                    dic.Item(dic.Count) = RangeToArr(.Range(.Cells(b, 1), .Cells(y - 1, 3)))
                    b = 0
                End If
            Else
                If Mid(arr(y, 1), 3, 1) = "-" Then
                    If b > 0 Then
                        dic.Item(dic.Count) = RangeToArr(.Range(.Cells(b, 1), .Cells(y - 1, 3)))
                    End If
                    b = y
                End If
            End If
        Next
    End With
    Set GetDic = dic
End Function

Private Function RangeToArr(r As Range) As Variant
    
    Dim s As String
    Dim y As Long
    Dim x As Byte
    Dim arr As Variant
    arr = r
    
    Dim brr As Variant
    ReDim brr(1 To 2)
    
    Dim crr As Variant
    ReDim crr(1 To 1, 1 To 3)
    
    For x = 1 To 3
        crr(1, x) = arr(1, x)
    Next
    brr(1) = crr
    For y = 2 To UBound(arr, 1)
        For x = 1 To UBound(arr, 2)
            s = s & arr(y, x) & vbTab
        Next
    Next
    brr(2) = s
    
    RangeToArr = brr
End Function
 
Jack Famous, думаю, раз все макросы в данной теме от пользователя МатросНаЗебре, то ему принадлежит первоочередность :) В случае, конечно, если он согласен.

МатросНаЗебре, попробовал оба макроса. Намного быстрее стал отрабатываться на малых и средних объёмах. Выражаю в очередной раз благодарность!)

А на большом массиве (злосчастные 3080 - 25628 строк) индекс выходит за пределы допустимого диапазона (9 ошибка).

Код
brr(y + 1, x) = arr(2, x)

Так что разбил таблицы на три части и запустил на каждой макрос. Далее вручную производится выборка для последнего сравнения. Для каждого дублирующего списка таблиц остаётся только первая таблица и добавляются все уникальные.

Ещё интересно, что эти 3080 таблиц отработались еще по первой версии макроса (21.04), но не полностью (пропустилось около 50% таблиц).

 
Цитата
Сироп Клубничный: все макросы в данной теме от пользователя МатросНаЗебре, то ему принадлежит первоочередность
я предлагаю, а не отбираю - как хотите, так и поступайте  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Я про первоочерёдность не понял. Вроде, не было очереди.
Если у Джека и Сиропа есть желание договориться о другом выполнении задачи, то я не против.

Интересно, конечно, увидеть реализацию в сотни раз быстрее. Если речь про VBA.
Я не ставлю под сомнение возможность такой реализации, действительно было бы интересно посмотреть.
 
А так? Вроде, должна уйти ошибка выхода за границы допустимого диапазона.
Код
Option Explicit
  
Sub АргентинаБразилия()
    Dim dt As Date: dt = Now
 
    Dim dic As Object
    Set dic = GetDic()
            
    If dic.Count > 0 Then
        Dim ar1 As Variant
        Dim ar2 As Variant
        CompareTb dic, ar1, ar2, True
        CompareTb dic, ar1, ar2, False
    End If
        
    Dim rOut As Range
    Set rOut = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    OutArr ar1, rOut
    OutArr ar2, rOut.Cells(1, 5)
     
    Debug.Print Format(Now - dt, "nn:ss") & " строка"
End Sub
    
Private Sub OutArr(arr As Variant, rOut As Range)
    With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))
        .NumberFormat = "@"
        .Cells = arr
        .EntireColumn.AutoFit
    End With
    rOut.Parent.Parent.Saved = True
End Sub
    
Private Function CompareTb(dic As Object, ByRef arrIn1 As Variant, ByRef arrIn2 As Variant, compareMod As Boolean) As Boolean
    Dim arr As Variant
     ReDim arr(1 To 2, 1 To 3)
      
    Dim ar2 As Variant
     ReDim ar2(1 To 1, 1 To 3)
      
    Dim col1 As New Collection
    Dim col2 As New Collection
      
    Dim u As Long
    Dim i As Long
    Dim j As Long
    Dim w As Long
    Dim y As Long
    Dim x As Byte
    Dim irr As Variant
    Dim jrr As Variant
    Dim f As Boolean
    Dim atLeastOne As Boolean
    For i = 0 To dic.Count - 2
        irr = dic.Items()(i)
        atLeastOne = False
        For j = IIf(compareMod, i + 1, 0) To dic.Count - 1
            If i <> j Then
                jrr = dic.Items()(j)
                If Len(irr(2)) = Len(jrr(2)) Then
                    If irr(2) = jrr(2) Then
                        u = u + 3
                        For x = 1 To UBound(irr(1), 2)
                            arr(1, x) = irr(1)(1, x)
                            arr(2, x) = jrr(1)(1, x)
                        Next
                        col1.Add arr
                        atLeastOne = True
                    End If
                End If
            End If
        Next
        If atLeastOne = False Then
            w = w + 3
            For x = 1 To UBound(irr(1), 2)
                ar2(1, x) = irr(1)(1, x)
            Next
            col2.Add ar2
        End If
    Next
       
    If compareMod Then
        u = u + 1
        If u > Application.Rows.Count Then u = Application.Rows.Count
           
        Dim brr As Variant
        ReDim brr(1 To u + 3, 1 To 3)
        y = 1
        For Each arr In col1
            For x = 1 To 3
                brr(y + 0, x) = arr(1, x)
                brr(y + 1, x) = arr(2, x)
            Next
            y = y + 3
        Next
         
        arrIn1 = brr
    Else
        w = w + 1
        If w > Application.Rows.Count Then w = Application.Rows.Count
 
 
        ReDim brr(1 To w, 1 To 3)
        y = 1
        For Each arr In col2
            For x = 1 To 3
                brr(y, x) = arr(1, x)
            Next
            y = y + 2
        Next
 
        arrIn2 = brr
    End If
       
    CompareTb = True
End Function
    
    
Private Function GetDic() As Object
    Dim sh As Worksheet
    Set sh = ActiveSheet
    With sh
        Dim y As Long
        Dim arr As Variant
        y = .Cells(.Rows.Count, 1).End(xlUp).Row
        arr = .Range(.Cells(1, 1), .Cells(y + 1, 1))
            
        Dim b As Long
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        For y = 3 To UBound(arr, 1)
            If IsEmpty(arr(y, 1)) Then
                If b > 0 Then
                    dic.Item(dic.Count) = RangeToArr(.Range(.Cells(b, 1), .Cells(y - 1, 3)))
                    b = 0
                End If
            Else
                If Mid(arr(y, 1), 3, 1) = "-" Then
                    If b > 0 Then
                        dic.Item(dic.Count) = RangeToArr(.Range(.Cells(b, 1), .Cells(y - 1, 3)))
                    End If
                    b = y
                End If
            End If
        Next
    End With
    Set GetDic = dic
End Function
 
Private Function RangeToArr(r As Range) As Variant
     
    Dim s As String
    Dim y As Long
    Dim x As Byte
    Dim arr As Variant
    arr = r
     
    Dim brr As Variant
    ReDim brr(1 To 2)
     
    Dim crr As Variant
    ReDim crr(1 To 1, 1 To 3)
     
    For x = 1 To 3
        crr(1, x) = arr(1, x)
    Next
    brr(1) = crr
    For y = 2 To UBound(arr, 1)
        For x = 1 To UBound(arr, 2)
            s = s & arr(y, x) & vbTab
        Next
    Next
    brr(2) = s
     
    RangeToArr = brr
End Function
 
Цитата
МатросНаЗебре написал:
А так?
То же - строка 91. Все равно выходит за диапазон
 
Надо смотреть файл. Пример пролезет на форум?
 
Если немного сократить текстовое наполнение и сохранить в двоичном формате, то пролезает :)  
 
Тогда так.
Результат выводится в текстовые файлы, находящиеся рядом с файлом с макросом.
Файлы открываются по мере заполнения. Дождитесь открытия второго текстового файла.
Код
Option Explicit

Sub АргентинаЧили()
    Dim dt As Date: dt = Now
  
    Dim dic As Object
    Set dic = GetDic()
    If dic.Count = 0 Then Exit Sub
                 
    Dim arrDic As Variant
    arrDic = DicToArr(dic)
    Set dic = Nothing
                 
    Dim ar1 As Variant
    Dim ar2 As Variant
    CompareTb arrDic, ar1, ar2, True
    CompareTb arrDic, ar1, ar2, False
         
'    Dim rOut As Range
'    Set rOut = Workbooks.Add(1).Sheets(1).Cells(1, 1)
'    OutArr ar1, rOut
'    OutArr ar2, rOut.Cells(1, 5)
      
    Debug.Print Format(Now - dt, "nn:ss") & " Чили"
End Sub
     
Private Function DicToArr(dic As Object) As Variant
    Dim arr As Variant
    ReDim arr(1 To dic.Count)
    Dim i As Long
    For i = 1 To UBound(arr)
        arr(i) = dic.Items()(i - 1)
    Next
    DicToArr = arr
End Function
     
Private Sub OutArr(arr As Variant, rOut As Range)
    With rOut.Cells(1).Resize(UBound(arr, 1), UBound(arr, 2))
        .NumberFormat = "@"
        .Cells = arr
        .EntireColumn.AutoFit
    End With
    rOut.Parent.Parent.Saved = True
End Sub
     
Private Function CompareTb(arrDic As Variant, ByRef arrIn1 As Variant, ByRef arrIn2 As Variant, compareMod As Boolean) As Boolean
    Dim arr As Variant
     ReDim arr(1 To 2, 1 To 3)
       
    Dim ar2 As Variant
    ReDim ar2(1 To 1, 1 To 3)
       
    Dim col1 As New Collection
    Dim col2 As New Collection
       
    Dim u As Long
    Dim i As Long
    Dim j As Long
    Dim w As Long
    Dim y As Long
    Dim x As Byte
    Dim irr As Variant
    Dim jrr As Variant
    Dim f As Boolean
    Dim atLeastOne As Boolean
    
    Dim sFile As String
    sFile = ThisWorkbook.Path & "\" & IIf(compareMod, "совпадают", "хоть1") & ".txt"
    
    Dim ts As Object
    Set ts = CreateObject("Scripting.FileSystemObject").CreateTextFile(sFile, True)
    
    Dim s As String
    
    For i = 1 To UBound(arrDic) - 1 '- 2
        DoEvents
        Debug.Print Now, UBound(arrDic) - 1 - i
        irr = arrDic(i)
        atLeastOne = False
        For j = IIf(compareMod, i + 1, 1) To UBound(arrDic) '- 1
            If i <> j Then
                jrr = arrDic(j)
                If Len(irr(2)) = Len(jrr(2)) Then
                    If irr(2) = jrr(2) Then
'                        u = u + 3
'                        For x = 1 To UBound(irr(1), 2)
'                            arr(1, x) = irr(1)(1, x)
'                            arr(2, x) = jrr(1)(1, x)
'                        Next
'                        col1.Add arr
                        
                        s = ""
                        For x = 1 To UBound(irr(1), 2)
                            s = s & irr(1)(1, x) & vbTab
                        Next
                        s = s & vbCrLf
                        For x = 1 To UBound(irr(1), 2)
                            s = s & jrr(1)(1, x) & vbTab
                        Next
                        s = s & vbCrLf & vbCrLf
                        ts.Write s
                        
                        atLeastOne = True
                    End If
                End If
            End If
        Next
        If atLeastOne = False Then
'            w = w + 3
'            For x = 1 To UBound(irr(1), 2)
'                ar2(1, x) = irr(1)(1, x)
'            Next
'            col2.Add ar2
            
            
            s = ""
            For x = 1 To UBound(irr(1), 2)
                s = s & irr(1)(1, x) & vbTab
            Next
            s = s & vbCrLf & vbCrLf
            ts.Write s
        End If
    Next
        
'    If compareMod Then
'        u = u + 1
'        If u > Application.Rows.Count Then u = Application.Rows.Count
'
'        Dim brr As Variant
'        ReDim brr(1 To u + 3, 1 To 3)
'        y = 1
'        For Each arr In col1
'            For x = 1 To 3
'                brr(y + 0, x) = arr(1, x)
'                brr(y + 1, x) = arr(2, x)
'            Next
'            y = y + 3
'        Next
'
'        arrIn1 = brr
'    Else
'        w = w + 1
'        If w > Application.Rows.Count Then w = Application.Rows.Count
'
'
'        ReDim brr(1 To w, 1 To 3)
'        y = 1
'        For Each arr In col2
'            For x = 1 To 3
'                brr(y, x) = arr(1, x)
'            Next
'            y = y + 2
'        Next
'
'        arrIn2 = brr
'    End If
        
    ts.Close
    If Dir(sFile) <> "" Then Shell "explorer.exe """ & sFile & """", 1
    
    CompareTb = True
End Function
     
     
Private Function GetDic() As Object
    Dim sh As Worksheet
    Set sh = ActiveSheet
    With sh
        Dim y As Long
        Dim arr As Variant
        y = .Cells(.Rows.Count, 1).End(xlUp).Row
        arr = .Range(.Cells(1, 1), .Cells(y + 1, 1))
             
        Dim b As Long
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        For y = 3 To UBound(arr, 1)
            If IsEmpty(arr(y, 1)) Then
                If b > 0 Then
                    dic.Item(dic.Count) = RangeToArr(.Range(.Cells(b, 1), .Cells(y - 1, 3)))
                    b = 0
                End If
            Else
                If Mid(arr(y, 1), 3, 1) = "-" Then
                    If b > 0 Then
                        dic.Item(dic.Count) = RangeToArr(.Range(.Cells(b, 1), .Cells(y - 1, 3)))
                    End If
                    b = y
                End If
            End If
        Next
    End With
    Set GetDic = dic
End Function
  
Private Function RangeToArr(r As Range) As Variant
      
    Dim s As String
    Dim y As Long
    Dim x As Byte
    Dim arr As Variant
    arr = r
      
    Dim brr As Variant
    ReDim brr(1 To 2)
      
    Dim crr As Variant
    ReDim crr(1 To 1, 1 To 3)
      
    For x = 1 To 3
        crr(1, x) = arr(1, x)
    Next
    brr(1) = crr
    For y = 2 To UBound(arr, 1)
        For x = 1 To UBound(arr, 2)
            s = s & arr(y, x) & vbTab
        Next
    Next
    brr(2) = s
      
    RangeToArr = brr
End Function
 
Получается не хватало строк для Экселя? :D  
 
Не хватало, но только не строк, а памяти компа. Обработку для количества строк я делал.
Страницы: 1
Наверх