Home > Enterprise >  Golang print all permutations of an array of arrays
Golang print all permutations of an array of arrays

Time:09-08

Looking for a method that will print all combinations of an array of arrays.

Data type would look something like this:

// print all combos
var data [][]string

Example

Input: [[Lorem, Ipsum], [Alpha, Beta, Theta]]

Expected Output: Lorem Alpha, Lorem Beta, Lorem Theta, Ipsum Alpha, Ipsum Beta, Ipsum Theta

The arrays can be of arbitrary length. What's the best way to accomplish this?

CodePudding user response:

I'd iterate the vector of indexes of the slices.

Single index iterator:

// Iterator of a slice index. `len` equals to the length of the slice
type IdxIter struct {
    idx uint
    len uint
}

// Returns true is the iteration is over.
func (i IdxIter) Done() bool {
    return i.idx >= i.len
}

// Builds the next iteration value. If called for the last index,
// the next value's `Done` returns `true`.
func (i *IdxIter) Next() {
    i.idx  
}

// Resets the iterator
func (i *IdxIter) Reset() {
    i.idx = 0
}

// The index value
func (i IdxIter) Idx() uint {
    return i.idx
}

Iterator of a vector of indexes:

// Index iterator for a slice of slices
type IdxVectorIter []IdxIter

// Returns true is the iteration is over.
func (ii IdxVectorIter) Done() bool {
    last := len(ii) - 1
    return ii[last].Done()
}

// Builds the next iteration value. If called for the last index vector,
// the next value's `Done` returns `true`.
func (ii IdxVectorIter) Next() {
    if len(ii) == 0 {
        return
    }
    last := len(ii) - 1
    for pos := range ii[:last] {
        ii[pos].Next()
        if ii[pos].Done() {
            ii[pos].Reset()
        } else {
            return
        }
    }
    ii[last].Next()
}

With that the iteration over the slice of slices is simple:

func main() {
    words := [][]string{
        {"lorem", "ipsum"},
        {},
        {"Alpha", "Beta", "Gamma"},
        {"X", "Y", "Z"},
    }
    // Fixed buffer for the combinations of words
    dst := make([]string, len(words))
    // Iteration loop
    for ii := NewIdxVectorFromSlices(words); !ii.Done(); ii.Next() {
        GetTo(words, dst, ii)
        fmt.Printf("%v\n", dst)
    }
}

Full code https://go.dev/play/p/ecjjcAEexZO

Output

[lorem  Alpha X]
[ipsum  Alpha X]
[lorem  Beta X]
[ipsum  Beta X]
[lorem  Gamma X]
[ipsum  Gamma X]
[lorem  Alpha Y]
[ipsum  Alpha Y]
[lorem  Beta Y]
[ipsum  Beta Y]
[lorem  Gamma Y]
[ipsum  Gamma Y]
[lorem  Alpha Z]
[ipsum  Alpha Z]
[lorem  Beta Z]
[ipsum  Beta Z]
[lorem  Gamma Z]
[ipsum  Gamma Z]
  • Related