Страницы: 1
RSS
Перебор всех вариантов значений столбцов таблицы 3x3 или 4x2 и т.п, Комбинаторика слишком сложна, возможно ли проще?
 
Приветствую!

Подскажите пожалуйста как получить все варианты значений из например такой таблицы:
1-00-20-0
0-00-01-1
0-10-11-0
На выходе нужны варианты построчно
1-00-20-0
0-00-21-1
0-10-21-0
в этом случае первые две ячейки первой строки остаются, последняя меняется с нижними вариантами
0-00-20-0
0-00-01-1
0-00-11-0
в этом случае второй вариант первого столбца остается и остальные значения остаются.
Но допустим значение из третьего столбца не должно перебраться в первый столбец, варианты должны быть строго в пределах своих столбцов.

Т.е. суть - это получить все варианты для каждого столбца из 3х строк
Ничего подобного в интернетах не нашел.

Возможно я ошибаюсь, но в итоге должно быть 27 вариантов


Аналогичное решение хотелось бы и для таблицы с 4 столбцами и 2 строками.

Благодарю  
 
у меня есть стандартная функция, которая на входе берет массив из произвольного количества строк с произвольным количеством элементов в каждой строке, а на выходе выдает все возможные комбинации содержащие по 1 значению из каждой строки
начиная с А1 разместите свои данные (4 столб. и 2 стр.), жмите кнопку, получите желаемые 16 комбинаций значений
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Игорь, благодарю!
То, что нужно! Работает и с доп столбцами.
Щиро дякую :)
 
Вечер добрый Всем, в продолжении этой темы пожалуйста подредактируйте макрос, сейчас все выбранные комбинации вставляются в один столбец "G", а задача состоит в том чтоб каждая комбинация вписывалась раздельно по одному значению в таблицу из 5-ти столбцов с "G:K", пример прилагаю
С уважением Тиго.
 
Здравствуйте.
Посмотрите так пойдет?
 
Алексей благодарствую, то что нужно было для решении моей задачи, если ещё поможете чтоб он  не выдавал ошибку если в таблице данных значений не все ячейки заполнены а выводил все варианты с учётом пустых ячеек пример прилагаю  
С уважением Тиго.
 
Код
Option Explicit

Sub Перебор()
    PereborRange Columns("A:C"), Columns("E:E"), Columns("G:I"), Columns("K:K")
End Sub

Private Sub PereborRange(ra As Range, rb As Range, printA As Variant, printB As Variant)
    Dim aic As Variant
    aic = GetAllValueFromRange(ra)
    Dim bic As Variant
    bic = GetAllValueFromRange(rb)
    
    Dim yp As Long
    yp = UBound(aic) + 1
    yp = yp * (UBound(bic) + 1)
    
    Dim pra As Variant, prb As Variant
    ReDim pra(1 To yp, 1 To UBound(Split(aic(0), "#")) + 1)
    ReDim prb(1 To yp, 1 To UBound(Split(bic(0), "#")) + 1)
    
    Dim aa As Variant, bb As Variant, arr As Variant, xp As Long
    yp = 0
    For Each aa In aic
        For Each bb In bic
            yp = yp + 1
            arr = Split(aa, "#")
            For xp = 1 To UBound(arr) + 1
                pra(yp, xp) = arr(xp - 1)
            Next
        
            arr = Split(bb, "#")
            For xp = 1 To UBound(arr) + 1
                prb(yp, xp) = arr(xp - 1)
            Next
        Next
    Next
    
    printA.Resize(1, UBound(pra, 2)).EntireColumn.ClearContents
    printB.Resize(1, UBound(prb, 2)).EntireColumn.ClearContents
    
    printA.Resize(UBound(pra, 1), UBound(pra, 2)).Value = pra
    printB.Resize(UBound(prb, 1), UBound(prb, 2)).Value = prb
End Sub

Private Function GetAllValueFromRange(rr As Range) As Variant
    
    Dim arr As Variant
    arr = GetResizedArrayValue(rr)
    
    Dim rowsHasEmpty As Object
    Set rowsHasEmpty = CreateObject("Scripting.Dictionary")
    Dim ya As Long, xa As Long
    For xa = 1 To UBound(arr, 2)
        For ya = 1 To UBound(arr, 1)
            If IsEmpty(arr(ya, xa)) Then
                rowsHasEmpty(ya) = Empty
            End If
        Next
    Next
    
    Dim columnNoEmptyInEmptyRow As Object
    Set columnNoEmptyInEmptyRow = CreateObject("Scripting.Dictionary")
    Dim vy As Variant
    For Each vy In rowsHasEmpty
        For xa = 1 To UBound(arr, 2)
            If Not IsEmpty(arr(vy, xa)) Then
                columnNoEmptyInEmptyRow(xa) = Empty
            End If
        Next
    Next
    
    Dim fixed As Variant, sKey As String, fic As Object
    Set fic = CreateObject("Scripting.Dictionary")
    For ya = 1 To UBound(arr, 1)
        For xa = 1 To UBound(arr, 2)
            If Not IsEmpty(arr(ya, xa)) Then
                If Not columnNoEmptyInEmptyRow.Exists(xa) Then
                    GoTo HasFixedColumn
                End If
            End If
        Next
        GoTo NextYa
HasFixedColumn:
        ReDim fixed(1 To UBound(arr, 2))
        For xa = 1 To UBound(arr, 2)
            If Not columnNoEmptyInEmptyRow.Exists(xa) Then
                fixed(xa) = arr(ya, xa)
            End If
        Next
        sKey = Join(fixed, "#")
        fic(sKey) = Empty
NextYa:
    Next
    
    Dim eic As Object
    Set eic = CreateObject("Scripting.Dictionary")
    For ya = 1 To UBound(arr, 1)
        fixed = Empty
        
        For xa = 1 To UBound(arr, 2)
            If Not IsEmpty(arr(ya, xa)) Then
                If columnNoEmptyInEmptyRow.Exists(xa) Then
                    If IsEmpty(fixed) Then ReDim fixed(1 To UBound(arr, 2))
                    fixed(xa) = arr(ya, xa)
                End If
            End If
        Next
        If Not IsEmpty(fixed) Then
            sKey = Join(fixed, "#")
            eic(sKey) = Empty
        End If
    Next
    
    If eic.Count > 0 Then
        Dim dic As Object
        Set dic = CreateObject("Scripting.Dictionary")
        Dim vv As Variant, ww As Variant, emted As Variant, sumed As Variant
        For Each vv In fic
            For Each ww In eic
                fixed = Split(vv, "#")
                emted = Split(ww, "#")
                sumed = SumArray(fixed, emted)
                sKey = Join(sumed, "#")
                dic(sKey) = Empty
            Next
        Next
        GetAllValueFromRange = dic.Keys()
    Else
        GetAllValueFromRange = fic.Keys()
    End If
    
End Function

Private Function SumArray(arr As Variant, brr As Variant) As Variant
    Dim srr As Variant, ys As Long
    ReDim srr(LBound(arr) To UBound(arr))
    For ys = LBound(srr) To UBound(srr)
        If arr(ys) <> "" Then
            srr(ys) = arr(ys)
        ElseIf brr(ys) <> "" Then
            srr(ys) = brr(ys)
        End If
    Next
    SumArray = srr
End Function

Private Function GetResizedArrayValue(rr As Range) As Variant
    Dim arr As Variant
    arr = Intersect(rr, rr.Parent.UsedRange).Value
    
    Dim yMax As Long, ya As Long, xa As Long
    For xa = 1 To UBound(arr, 2)
        For ya = UBound(arr, 1) To 1 Step -1
            If Not IsEmpty(arr(ya, xa)) Then
                If yMax < ya Then
                    yMax = ya
                    If yMax = UBound(arr, 1) Then GoTo FoundYmax
                End If
            End If
        Next
    Next
FoundYmax:
    Set rr = rr.Resize(yMax)
    If rr.Cells.CountLarge = 1 Then
        ReDim arr(1 To 1, 1 To 1)
        arr(1, 1) = rr.Value
    Else
        arr = rr.Value
    End If
    GetResizedArrayValue = arr
End Function
 
Рекурсивный вариант.
Код
Option Explicit

Sub Перебор_рекурсивный()
    PereborRangeRecu Columns("A:C"), Columns("E:E"), Columns("G:I"), Columns("K:K")
End Sub

Private Sub PereborRangeRecu(ra As Range, rb As Range, printA As Variant, printB As Variant)
    Dim aic As Variant
    aic = GetAllValueFromRange(ra)
    Dim bic As Variant
    bic = GetAllValueFromRange(rb)
    
    Dim yp As Long
    yp = UBound(aic) + 1
    yp = yp * (UBound(bic) + 1)
    
    Dim pra As Variant, prb As Variant
    ReDim pra(1 To yp, 1 To UBound(FromKey(aic(0))) + 1)
    ReDim prb(1 To yp, 1 To UBound(FromKey(bic(0))) + 11)
    
    Dim aa As Variant, bb As Variant, arr As Variant, xp As Long
    yp = 0
    For Each aa In aic
        For Each bb In bic
            yp = yp + 1
            arr = FromKey(aa)
            For xp = 1 To UBound(arr) + 1
                pra(yp, xp) = arr(xp - 1)
            Next
        
            arr = FromKey(bb)
            For xp = 1 To UBound(arr) + 1
                prb(yp, xp) = arr(xp - 1)
            Next
        Next
    Next
    
    printA.Resize(1, UBound(pra, 2)).EntireColumn.ClearContents
    printB.Resize(1, UBound(prb, 2)).EntireColumn.ClearContents
    
    printA.Resize(UBound(pra, 1), UBound(pra, 2)).Value = pra
    printB.Resize(UBound(prb, 1), UBound(prb, 2)).Value = prb
End Sub

Private Function GetAllValueFromRange(ra As Range) As Variant
    Dim arr As Variant
    arr = GetResizedArrayValue(ra)

    Dim dic As Object, sKey As String
    Set dic = CreateObject("Scripting.Dictionary")
    Dim ya As Long
    For ya = 1 To UBound(arr, 1)
        sKey = GetKey2(arr, ya)
        dic(sKey) = Empty
    Next
    
    Dim brr As Variant
    brr = dic.Keys()
    Set dic = CreateObject("Scripting.Dictionary")
    FillByRecu dic, brr
    brr = RemoveDup(dic.Keys())
    
    Set dic = CreateObject("Scripting.Dictionary")
    Dim vb As Variant, vc As Variant, crr As Variant, summed As Variant, hasEmpty As Boolean
    For Each vb In brr
        crr = FromKey(vb)
        ReDim summed(0 To UBound(arr, 2) - 1)
        For Each vc In crr
            sumArrays summed, FromKey(GetKey2(arr, CLng(vc) + 1))
        Next
        hasEmpty = False
        For Each vc In summed
            If vc = "" Then
                hasEmpty = True
                Exit For
            End If
        Next
        If Not hasEmpty Then
            sKey = GetKey1(summed)
            dic(sKey) = Empty
        End If
    Next
    
    GetAllValueFromRange = dic.Keys
End Function

Private Sub sumArrays(summed As Variant, arr As Variant)
    Dim ya As Long
    For ya = LBound(arr) To UBound(arr)
        If IsEmpty(summed(ya)) Or summed(ya) = "" Then
            summed(ya) = arr(ya)
        End If
    Next
End Sub

Private Function RemoveDup(arr As Variant) As Variant
    Dim dic As Object
    Set dic = CreateObject("Scripting.Dictionary")
    Dim bic As Object
    Set bic = CreateObject("Scripting.Dictionary")
    
    Dim va As Variant, vb As Variant, hasDupies As Boolean
    For Each va In arr
        hasDupies = False
        Set bic = CreateObject("Scripting.Dictionary")
        For Each vb In FromKey(va)
            If bic.Exists(vb) Then
                hasDupies = True
                Exit For
            Else
                bic(vb) = Empty
            End If
        Next
        If Not hasDupies Then dic(va) = Empty
    Next
    
    RemoveDup = dic.Keys()
End Function

Private Sub FillByRecu(dic As Object, arr As Variant)
    Dim ind As Variant, sKey As String
    ReDim ind(LBound(arr) To UBound(arr)) As Long
    
    Do
        sKey = GetKey1(ind)
        dic(sKey) = Empty
        recuPlus ind, LBound(ind)
        If ind(UBound(ind)) > UBound(ind) Then Exit Do
        DoEvents
    Loop
End Sub

Private Sub recuPlus(ind As Variant, level As Long)
    ind(level) = ind(level) + 1
    If ind(level) > UBound(ind) Then
        If level = UBound(ind) Then
            
        Else
            Dim xi As Long
            For xi = LBound(ind) To level
                ind(level) = 0
            Next
            recuPlus ind, level + 1
        End If
    End If
End Sub

Private Function GetKey1(brr As Variant) As String
    Dim arr As Variant
    ReDim arr(LBound(brr) To UBound(brr)) As String
    Dim xa As Long
    For xa = LBound(arr) To UBound(arr)
        arr(xa) = brr(xa)
    Next
    GetKey1 = Join(arr, "|")
End Function
Private Function GetKey2(arr As Variant, ya As Long) As String
    Dim brr As Variant
    ReDim brr(LBound(arr, 2) To UBound(arr, 2))
    Dim xa As Long
    For xa = LBound(arr, 2) To UBound(arr, 2)
        brr(xa) = arr(ya, xa)
    Next
    GetKey2 = Join(brr, "|")
End Function

Private Function FromKey(ByVal sKey As String) As Variant
    FromKey = Split(sKey, "|")
End Function

Private Function GetResizedArrayValue(rr As Range) As Variant
    Dim arr As Variant
    arr = Intersect(rr, rr.Parent.UsedRange).Value
    
    Dim yMax As Long, ya As Long, xa As Long
    For xa = 1 To UBound(arr, 2)
        For ya = UBound(arr, 1) To 1 Step -1
            If Not IsEmpty(arr(ya, xa)) Then
                If yMax < ya Then
                    yMax = ya
                    If yMax = UBound(arr, 1) Then GoTo FoundYmax
                End If
            End If
        Next
    Next
FoundYmax:
    Set rr = rr.Resize(yMax)
    If rr.Cells.CountLarge = 1 Then
        ReDim arr(1 To 1, 1 To 1)
        arr(1, 1) = rr.Value
    Else
        arr = rr.Value
    End If
    GetResizedArrayValue = arr
End Function
 
Уважаемый Матросназебре спасибо за отклик, но дело в том что по вашему коду выводятся не все комбинации (если я все правильно сделал) , файл приложил на втором листе я выложил три разных примера с данными и его вариантами комбинации так как пустыми могут быть любые разные столбцы с данными и даже два пустых
С уважением Тиго.
 
Попробуйте теперь.
 
Добрый вечер. Посмотрите вариант с простым перебором. Это просто набросок. Нужно выделить исходную таблицу и запустить макрос. Результат выводится начиная с ячейки I2.
Код
Sub Comb2()
 Dim Ar0, Nrw&, Ncl&, i&, j&, k&, l&, Se&, SRows&, Koef&, Ms&
 Ar0 = Selection.Value
 Nrw = UBound(Ar0, 1)
 Ncl = UBound(Ar0, 2)
 ReDim Ari(1 To Ncl)
 SRows = 1
 For i = 1 To Ncl
   Se = 0
   For j = 1 To Nrw
     If Ar0(j, i) <> "" Then Se = Se + 1
   Next j
   Ari(i) = IIf(Se = 0, 1, Se)
   SRows = SRows * Ari(i)
 Next i
 ReDim Arv(1 To SRows, 1 To Ncl)
 Koef = 1
 Ms = 1
 For i = Ncl To 1 Step -1
   j = 1
   Koef = Koef * Ari(i)
   While j <= SRows
     For k = 1 To Ari(i)
       For l = 1 To Ms
         Arv(j, i) = Ar0(k, i)
         j = j + 1
       Next l
     Next k
   Wend
   Ms = Ms * Ari(i)
 Next i
 Range("I2").Resize(SRows, Ncl) = Arv
End Sub
 
Старичок супер прям всё идеально как и нужно было, я выделение   Range("A1:E20").Select и очистку  Columns("I:M").ClearContents привязал к кнопке и всё чики - пики, Всем большое и огромное спасибо
С уважением Тиго.
Страницы: 1
Читают тему
Наверх