Получить все комбинации, где порядок первого элемента имеет значение, но порядок остальных не имеет - PullRequest
0 голосов
/ 31 января 2019

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

A
B
C
D

. Теперь я хочу ВСЕ комбинации из 3 букв из этих 4, где каждая буква должна занимать 1-ю позицию.Например,

ABC
ACD
ABD
BAC
BDA
BCA
CAB
CBD
CAD
...
etc

Примечание: ACB и ABC одинаковы, поскольку порядок следования 2-й и 3-й букв не имеет значения, но каждая буква должна отображаться на первой позиции. Так что я хочу толькоодин из 'ACB' и 'ABC'

Этот пример для 3 из 4, но я хочу что-то для 5 из 10. Может кто-нибудь помочь мне с этим?Я не могу найти формулу и пытался написать макрос / VBA, но не сработал.Буду очень признателен за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019
  • Эта проблема была действительно забавной, я нашел несколько алгоритмов Здесь и Здесь , которые могут получить комбинации из n элементов, но поворот вашего вопросавсе элементы в позиции 1 были действительно захватывающими.
  • Этот саб будет делать то, что вы просили, независимо от того, сколько у вас n-элементов (символов) и для любого r-места, которое вы хотите, до тех пор, пока r <= n.
  • Я пытался комментировать то, что я могу объяснить (хотя я оставил некоторые довольно трудные для того, чтобы получить строки, к которым я вернусь позже).

[РЕДАКТИРОВАТЬ]:

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

Option Base 1

Sub getCombinations()

    Dim ws As Worksheet, srcCol As String, desCol As String, places As Integer
    Dim lastRow As Integer, elements() As String, elmntsCount As Integer, nCr As Long, cmbnationCount As Long

    Set ws = ThisWorkbook.ActiveSheet 'Pick the sheet you're working on
    srcCol = "A" 'The column that has all the characters in singles
    desCol = "B" 'The column you wish to put the resulted combinations into

    lastRow = ws.Cells(ws.Rows.count, srcCol).End(xlUp).Row
    ReDim elements(1 To lastRow)
    For i = 1 To lastRow
        elements(i) = ws.Range(srcCol & i).Value2
    Next i

    elmntsCount = UBound(elements) - LBound(elements) + 1 'The total number of single elements (characters)

    Do
        places = InputBox("Enter the number of places (r):" & vbNewLine & "I.E, How many characters you want in each combination?" & vbNewLine & "(Places) must be <= " & elmntsCount, "Define the places", 3)
        If (places <= elmntsCount) Then Exit Do
        MsgBox "Places (r) must be less than or equal to the total count of characters (n) that are in column (" & srcCol & ")." & vbNewLine & "Please, choose a smaller integer for the (places)."
    Loop

    'To Calculate the number of combinations: first place takes all the possible elements and the rest of the places can be calculated using nCr
    'Where n is (total elements -1) and r is (total places -1).
    'So the total number of combinations will be: elmntsCount * nCr. And Excel has a built in function for nCr (COMBIN)
    nCr = Application.WorksheetFunction.Combin(elmntsCount - 1, places - 1) 'represents how many combinations are there disregarding the character in the first place
    cmbnationCount = elmntsCount * nCr

    MsgBox "There are " & cmbnationCount & " combinations." & vbNewLine & "I've put them in column (" & desCol & ")."

    ws.Range(desCol & 1 & ":" & desCol & cmbnationCount).ClearContents

    Dim comb As String, combCount As Long: combCount = 0
    Dim indices() As Integer, add As Integer: add = 0

    ReDim indices(1 To places)
    For i = 1 To places
        indices(i) = i
    Next i

    Do While (True)

        comb = ""
        'Write current combination
        For j = 1 To places
            comb = comb & elements(indices(j))
        Next j
        combCount = combCount + 1
        ws.Range(desCol & combCount).Value2 = comb

        'Locate last non-max index

        'For different combinations where order doesn't matter, The maximum index each place can have is (elmntsCount - places + i) where i is the index's nth place
        'So for 7 characters 4 places, the max index for the last place is 7-4+4 = 7. The one before it has a max of 7-4+3 = 6. So all the max indices are 4,5,6,7 in that order
        'But since we want to account for the possibility of some place having an index the same as the 1st place's index -given our special twist of the first place-,
        'then the max of each place's index become one less than the original max when the first place's index is greater than or equal to that place's index
        'And that's what the abs() part in the condition of the while loop is about:
        'When (first place's index) is greater than or equal to (the max index of the tested place) make that place's max index 1 less. Otherwise keep it as the original max
        i = places
        Do While (indices(i) = elmntsCount - places + i - Abs(indices(1) >= elmntsCount - places + i))
            i = i - 1
            If i = 1 Then
                'All indices after 1st index have maxed out
                indices(1) = indices(1) + 1
                If indices(1) > elmntsCount Then Exit Sub 'We've reached the end.
                indices(2) = 0
                i = 2
                'We've reached the first index, so increment it and start all over with the second one
                Exit Do
            End If
        Loop

        'Increment the current index, and if after the incremention it equals the first index, then add 1 more
        indices(i) = indices(i) + 1 + Abs((indices(i) + 1) = indices(1)) 'The absolute value part adds 1 if the index after incremention equals the first index, and adds 0 otherwise

        'Increment the following indices
        For j = i + 1 To places
            If (indices(j - 1) + 1) = indices(1) Then add = 1 'Check if an index after incrementing would equal the first index, and add 1 if so
            indices(j) = indices(j - 1) + 1 + add 'Each index is (1+add) more than the index before it
            add = 0
        Next j
    Loop
End Sub
0 голосов
/ 22 февраля 2019

Я считаю, что это 2 шага: 1. взять 3 буквы из 4 2. составить комбинацию из этих 3 букв.Мой результат, как показано ниже: ABC ACB BAC BCA CBA CAB ABD ADB BAD BDA DBA DAB ACD АЦП CAD CDA DCA DAC BCD BDC CBD CDB DCB DBC

...