0

Let's say I have the following array of arrays:

A = [
  ['a', 'b', 'c'],
  ['d', 'e', 'f'],
  ['g', 'h'],
  ['i'],
  ['j', 'k', 'l']
]

I want to find all possible combinations of the elements of each array with the elements of the other arrays (i.e. 'adgij' is one possibility but not 'abcde').

I can brute force it and just loop everything like this (javascript):

var A = [
      ['a', 'b', 'c'],
      ['d', 'e', 'f'],
      ['g', 'h'],
      ['i'],
      ['j', 'k', 'l']
    ],
    combinations,
    newCombinations = [];

A.forEach(function(a, index) {
  newCombinations = [];

  if (index === 0) {
    newCombinations = a;
  } else {
    a.forEach(function(val){
      combinations.forEach(function(combination){
        newCombinations.push(combination + val);
      });
    });
  }

  combinations = newCombinations;
});

The problem with this method is that it is breadth-first, so if I want to stop after n iterations I would have incomplete combinations.

Is there a way to get all possible combinations using depth-first method?

Raz
  • 8,981
  • 4
  • 19
  • 18
  • If I understand the question correctly, you should search for "depth-first cartesian product". Here is one link I found: https://gist.github.com/andreasvc/5455646 – Raman Jan 08 '14 at 02:19
  • This might be a duplicate of: http://stackoverflow.com/questions/3621268/algorithm-to-produce-cartesian-product-of-arrays-in-depth-first-order – Raman Jan 08 '14 at 02:22

2 Answers2

2

A simple recursive function in pseudo-code.

Each recursive step picks one of the elements from the current index's array, and calls the function for the next index.

current can just be a list.

printAllCombinations(A, {}, 0)

printAllCombinations(A, current, index)
  if index == A.length
    print current
    return
  for each element e in A[index]
    current.addToBack(e)
    printAllCombinations(A, current, index + 1)
    current.removeLast(e)
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
0

I've basically created a map (for instance [0,0,0,0,0] would select all first members in your list of lists while [2,2,1,0,2] will select all last members) in python to numbers and then translated back to the list. It's a bit tricky but I hope I'm right:

#!/usr/bin/env python
import itertools

def map_good_opt(good_opt, A):
    return [i[1][i[0]] for i in zip(good_opt, A)]

if "__main__" == __name__:

    # your list of lists    
    A = [
          ['a', 'b', 'c'],
          ['d', 'e', 'f'],
          ['g', 'h'],
          ['i'],
          ['j', 'k', 'l']
        ]

    # this part generates all options (a bit more actually...)
    m = max(len(a) for a in A)
    print "m : %d" % m
    nums = range(m)
    print "nums: %r" % str(nums)
    opts = itertools.product(nums, repeat=len(A))       

    # now we have all number 00000 - 33333
    # we don't want 33333 or anything higher than len(A[i]) for each list in A 
    opts = itertools.product(nums, repeat=len(A))
    # this removes all bad options... (I hope :D)
    good_opts = [opt for opt in opts if len([i for i in range(len(A)) if (opt[i] < len(A[i]))]) == len(A)]

    # and we're left with the good options
    for opts in good_opts:
        print str(opt)
    print "GO: %d" % len(good_opts)
    for g in good_opts:
        print str("OPTIONS: " + str(g))
        print str("MAPPED TO: " + str(map_good_opt(g,A)))
    print "done."

I only did this to learn itertools and zip which I've recently learned here in Stackoverflow, and your question looked interesting enough to test this on :) Good luck.

Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88