Depth-first combination algorithm

隐身守侯 提交于 2019-12-25 05:18:23

问题


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?


回答1:


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)



回答2:


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.



来源:https://stackoverflow.com/questions/20984495/depth-first-combination-algorithm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!