我今天处于一个位置,我需要列举所有可能的锯齿状列表组合.例如,一种天真的方法是:
for a in [1,2,3]: for b in [4,5,6,7,8,9]: for c in [1,2]: yield (a,b,c)
这是有用的,但在可以使用的列表数量方面不是通用的.这是一个更通用的方法:
from numpy import zeros, array, nonzero, max make_subset = lambda x,y: [x[i][j] for i,j in enumerate(y)] def combinations(items): num_items = [len(i) - 1 for i in items] state = zeros(len(items), dtype=int) finished = array(num_items, dtype=int) yield grab_items(items, state) while True: if state[-1] != num_items[-1]: state[-1] += 1 yield make_subset(items, state) else: incrementable = nonzero(state != finished)[0] if not len(incrementable): raise StopIteration rightmost = max(incrementable) state[rightmost] += 1 state[rightmost+1:] = 0 yield make_subset(items, state)
有关更好的方法或反对上述方法的理由的任何建议?
天真的方法可以更紧凑地编写为生成器表达式:
((a,b,c) for a in [1,2,3] for b in [4,5,6,7,8,9] for c in [1,2])
使用递归函数可以更简单地编写一般方法:
def combinations(*seqs): if not seqs: return (item for item in ()) first, rest = seqs[0], seqs[1:] if not rest: return ((item,) for item in first) return ((item,) + items for item in first for items in combinations(*rest))
样品用法:
>>> for pair in combinations('abc', [1,2,3]): ... print pair ... ('a', 1) ('a', 2) ('a', 3) ('b', 1) ('b', 2) ('b', 3) ('c', 1) ('c', 2) ('c', 3)