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

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

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

Все они различаются, например

E:
101%
105%
110%
120%

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

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

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

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

Ответ 1

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

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

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

Шаг 1

Организуйте массивы в столбцах.

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

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

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

enter image description here

Шаг 2

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

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

  • Дружественное имя для вашего подключения

  • выберите соответствующий драйвер Microsoft Excel

... then 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

Ответ 2

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

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. Еще один вариант, о котором я могу думать, - записать вывод в текстовый файл в таком сценарии. Если ваши данные малы, вы можете уйти без использования массивов и напрямую писать в ячейки.:) Но в случае больших данных я бы рекомендовал использовать массивы.

Ответ 3

Мне это нужно было несколько раз и, наконец, построил.

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

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

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

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

Как это работает (кратко): сначала для каждого столбца и для каждой строки: он вычисляет количество общих строк, необходимых для поддержки всех комбо в 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

Ответ 4

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

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

enter image description here

Вкл Sheet2:

enter image description here

Формулы

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

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

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

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

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

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

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

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

Ответ 5

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

Пример:

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