Search code examples
arraysexcelvbapermutation

Get all permutations of string array without duplicates for any element


I have a textbox on a sheet to get its value to be used as the criteria of AutoFilter.
The value of textbox is numbers and the multiplication factor is asterisk "*".
There is no issue if the value is only one string e.g "2" or "5".
But, there are cases that the string will be like "1*2" or "10*12*14"
The problem is order of the multiplied numbers differs from someone input to another one,
Meaning: "1*2" can be inputted as "2*1 by another one"
and "10*12*14" can be inputted as "12*10*14" or "14*12*10" and so on.
So, if the value of textbox contains multiplied numbers, then:
I need to get all possible permutations of string array without duplicates on any element (as stated earlier).
the expected result will be used as the criteria of AutoFilter.
I tried the below code and it dose not work as I need, as it produce a lot of duplicates of array elements.

Sub Main()
    
    Dim size As Long, c As Variant, n As Long, arr
    Dim tbx4 As String, factors() As String
    
    tbx4 = "10*12*14"  'ActiveSheet.TextBox4.value
        
    factors = Split(tbx4, "*")
    
    size = UBound(factors) + 1
    c = factors
    
    n = UBound(c) + 1:   ReDim arr(size - 1)
    
    EmbeddedLoops 0, size, c, n, arr
    
End Sub
 
Function EmbeddedLoops(index, k, c, n, arr)
  Dim i As Variant
    If index >= k Then
        PrintArrayOnSingleLine arr
    Else
        For Each i In c
            arr(index) = i
            EmbeddedLoops index + 1, k, c, n, arr
        Next i
    End If
End Function
 
Sub PrintArrayOnSingleLine(myArray As Variant)
  Dim counter As Integer, textArray As String
    For counter = LBound(myArray) To UBound(myArray)
        textArray = textArray & myArray(counter)
    Next counter
    Debug.Print textArray
End Sub

Solution

  • This is how I would do it:

    Option Explicit
    Sub Main()
        
        Dim n As Long, i As Long, k As Long, ptr As Long, possibles As Long, arr() As String
        Dim tbx4 As String, factors() As String
    
        tbx4 = "10*12*14*16*18"  'ActiveSheet.TextBox4.value
            
        factors = Split(tbx4, "*")
        
        n = UBound(factors)
        
        k = n
        possibles = n + 1
        
        Do While k > 1
            possibles = possibles * k
            k = k - 1
        Loop
        
        ReDim arr(possibles - 1)
        ptr = 0
        
        For i = 0 To n
            Call FillArray(arr, factors, ptr)
        Next
        
        Dim tmp As String
        For k = 0 To possibles - 1
            arr(k) = Right(arr(k), Len(arr(k)) - 1)
            Debug.Print arr(k)
        Next
        
        
    End Sub
     
    Sub FillArray(arr() As String, elements() As String, ByRef ptr As Long)
    
        Dim i As Integer, k As Integer, l As Integer, element As String, possibles As Integer, m As Integer
        Dim subelements() As String, subptr As Long
        Dim subarr() As String
        
        ptr = 0
        For i = 0 To UBound(elements)
            element = elements(i)
            If UBound(elements) > 0 Then
                ReDim subelements(UBound(elements) - 1)
                l = 0
                For k = 0 To UBound(elements)
                    If k <> i Then
                        subelements(l) = elements(k)
                        l = l + 1
                    End If
                Next
                possibles = UBound(subelements) + 1
                m = possibles - 1
                Do While m > 1
                    possibles = possibles * m
                    m = m - 1
                Loop
                ReDim subarr(possibles - 1)
                subptr = 0
                Call FillArray(subarr, subelements, subptr)
                If UBound(subelements) = 0 Then
                    arr(ptr) = "*" + element + "*" + subelements(0)
                    ptr = ptr + 1
                Else
                    For m = 0 To UBound(subarr)
                        arr(ptr) = "*" + element + subarr(m)
                        ptr = ptr + 1
                    Next
                End If
            End If
        Next
        
    
    End Sub
     
    

    By way of explanation. Firstly I calculate the number of possible permutations. For any number of factors n, the number of permutations is given by n * n - 1 * n - 2 ... until n - x is 1. Effectively we only need to go down to * 2, since * 1 yields the same answer. I then dimension the answer array accordingly.

    We then need an iterative function to fill this array with the possible values. Note that I am passing a pointer by reference into this function. This is because I am filling the answers by a fixed pattern, to ensure completeness. Take a,b,c,d as examples. There are 24 possible combinations: these I generate effectively in batches of six, starting with each of the given letters, so the first six in the answer begin with a and the last 6 with d. But my outer loop in this case would only run four times, hence the requirement for a pointer that gets advanced within the iterative function. Obviously your case is easier with only three factors, but I have written my answer to be extensible.