Excel vba для создания всех возможных комбинаций диапазона

У меня проблема, которую я не смог найти нигде в интернете (он может быть там, но я не могу найти его, хех).

У меня есть таблицы с 13 столбцами данных. Каждый столбец содержит вариации параметра, который должен входить в общий тестовый случай.

все они отличаются, как

E:
101%
105%
110%
120%

J:
Верхний S
Вверх L
Нижняя сторона Б
Премиум V

Я видел несколько решений проблемы комбинации, которая использует вложенные циклы. Я хотел бы держаться подальше от 13 вложенных циклов (но это мой лучший выбор на данный момент). Я в недоумении о том, как генерировать каждую уникальную комбинацию в каждом столбце.

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

Спасибо за любую помощь вы, ребята, можете дать мне.

5 ответов


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

это способ создать декартова произведения двух или более одномерных массивов данных с использованием Excel и Microsoft Query.

эти инструкции были написаны с XL2007, но должны работать с незначительными (если таковые имеются) изменениями в любых версия.

Шаг 1

упорядочить массивы по столбцам.

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

Выберите каждый диапазон данных по очереди, включая оба "заголовков", и нажмите Ctrl+Shift+F3. Только ТИК Top row В создать Имена " диалог и нажмите OK.

после того, как все именованные диапазоны установлены, сохраните файл.

enter image description here

Шаг 2

Данные / Получить Внешние Данные | Из Других Источников / Из Microsoft Query

выбрать <New Data Source>. В Choose New Data Source диалог:

  1. дружественное имя для вашего соединения

  2. выберите соответствующий Microsoft Excel водитель!--12-->

... тогда Connect

enter image description here

Шаг 3

Select Workbook... затем найдите файл.

enter image description here

Шаг 4

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

далее нажмите кнопку Cancel (на самом деле!). На этом этапе вам может быть предложено чтобы " продолжить редактирование в Microsoft Query?"(ответ Yes) или жалоба, которая присоединяется, не может быть представлена в графическом редакторе. Игнорируй это и продолжай...

enter image description here

Шаг 5

откроется Microsoft Query, и по умолчанию добавленные таблицы будут скрещены. Это создаст декартово произведение, чего мы и хотим.

теперь закройте MSQuery вообще.

enter image description here

шаг 6

вы возвращаетесь на лист. Почти готово, обещаю! ТИК New worksheet и OK.

enter image description here

Шаг 7

возвращаются результаты перекрестного соединения.

enter image description here


не уверен, почему вы не любите цикл. См. этот пример. Это заняло меньше секунды.

Option Explicit

Sub Sample()
    Dim i As Long, j As Long, k As Long, l As Long
    Dim CountComb As Long, lastrow As Long

    Range("G2").Value = Now

    Application.ScreenUpdating = False

    CountComb = 0: lastrow = 6

    For i = 1 To 4: For j = 1 To 4
    For k = 1 To 8: For l = 1 To 12
        Range("G" & lastrow).Value = Range("A" & i).Value & "/" & _
                                     Range("B" & j).Value & "/" & _
                                     Range("C" & k).Value & "/" & _
                                     Range("D" & l).Value
        lastrow = lastrow + 1
        CountComb = CountComb + 1
    Next: Next
    Next: Next

    Range("G1").Value = CountComb
    Range("G3").Value = Now

    Application.ScreenUpdating = True
End Sub

снимок

enter image description here

Примечание: выше был небольшой пример. Я сделал тест на 4 столбцах с 200 строками каждый. Общая комбинация, возможная в таком сценарии, -1600000000 и это заняло 16 секунд.

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


Я сам нуждался в этом несколько раз и, наконец, построил его.

Я считаю, что код масштабируется для любого общего количества столбцов и любого количества различных значений в Столбцах (например, каждый столбец может содержать любое количество значений)

предполагается, что все значения в каждом столбце уникальны (если это не так, вы будете получать повторяющиеся строки)

предполагается, что вы хотите объединить выходные данные на основе выбранных вами ячеек (убедитесь, что вы их выбрали все)

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

Как это работает (кратко): сначала для каждого столбца и для каждой строки: он вычисляет количество общих строк, необходимых для поддержки всех комбо в N столбцах (элементы в столбце 1 * элементы в столбце 2 ... * элементов в столбце N)

секунда для каждого столбца: на основе общих комбо и общих комбо предыдущих столбцов он вычисляет два цикла.

ValueCycles (сколько раз вам нужно перебрать все значения в текущем столбце) ValueRepeats (сколько раз повторять каждое значение в столбце последовательно)

Sub sub_CrossJoin()

Dim rg_Selection As Range
Dim rg_Col As Range
Dim rg_Row As Range
Dim rg_Cell As Range
Dim rg_DestinationCol As Range
Dim rg_DestinationCell As Range
Dim int_PriorCombos As Long
Dim int_TotalCombos As Long
Dim int_ValueRowCount As Long
Dim int_ValueRepeats As Long
Dim int_ValueRepeater As Long
Dim int_ValueCycles As Long
Dim int_ValueCycler As Long

int_TotalCombos = 1
int_PriorCombos = 1
int_ValueRowCount = 0
int_ValueCycler = 0
int_ValueRepeater = 0

Set rg_Selection = Selection
Set rg_DestinationCol = rg_Selection.Cells(1, 1)
Set rg_DestinationCol = rg_DestinationCol.Offset(0, rg_Selection.Columns.Count)

'get total combos
For Each rg_Col In rg_Selection.Columns
    int_ValueRowCount = 0
    For Each rg_Row In rg_Col.Cells
        If rg_Row.Value = "" Then
            Exit For
        End If
        int_ValueRowCount = int_ValueRowCount + 1
    Next rg_Row
    int_TotalCombos = int_TotalCombos * int_ValueRowCount
Next rg_Col

int_ValueRowCount = 0

'for each column, calculate the repeats needed for each row value and then populate the destination
For Each rg_Col In rg_Selection.Columns
    int_ValueRowCount = 0
    For Each rg_Row In rg_Col.Cells
        If rg_Row.Value = "" Then
            Exit For
        End If
        int_ValueRowCount = int_ValueRowCount + 1
    Next rg_Row
    int_PriorCombos = int_PriorCombos * int_ValueRowCount
    int_ValueRepeats = int_TotalCombos / int_PriorCombos


    int_ValueCycles = (int_TotalCombos / int_ValueRepeats) / int_ValueRowCount
    int_ValueCycler = 0

    int_ValueRepeater = 0

    Set rg_DestinationCell = rg_DestinationCol

    For int_ValueCycler = 1 To int_ValueCycles
        For Each rg_Row In rg_Col.Cells
            If rg_Row.Value = "" Then
                Exit For
            End If

                For int_ValueRepeater = 1 To int_ValueRepeats
                    rg_DestinationCell.Value = rg_Row.Value
                    Set rg_DestinationCell = rg_DestinationCell.Offset(1, 0)
                Next int_ValueRepeater

        Next rg_Row
    Next int_ValueCycler

    Set rg_DestinationCol = rg_DestinationCol.Offset(0, 1)
Next rg_Col
End Sub

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

Я начинаю с ваших выборочных данных. Для удобства я добавил графы в верхний ряд. Я также добавил общее количество комбинаций (произведение подсчетов). Это Sheet1:

enter image description here

On Sheet2:

enter image description here

Формулы:

A2:C2 (оранжевые ячейки) жестко закодированы =0

A3=IF(SUM(B3:C3)=0,MOD(A2+1,Sheet1!$E),A2)

B3=IF(C3=0,MOD(B2+1,Sheet1!$G),B2)

C3=MOD(C2+1,Sheet1!$J)

D2=INDEX(Sheet1!$E:$E,Sheet2!A2+1)

E2=INDEX(Sheet1!$G:$G,Sheet2!B2+1)

F2=INDEX(Sheet1!$J:$J,Sheet2!C2+1)

заполнить из строки 3 вниз столько строк, сколько Total показывает Sheet1


вызовите метод и поместите в текущий уровень, который будет уменьшен в методе (извините за eng)

пример:

    sub MyAdd(i as integer)
      if i > 1 then
        MyAdd = i + MyAdd(i-1)
      else
        MyAdd = 1
      end if
    end sub