Бьюсь об заклад, * решения на основе itertools
будут быстрее, но если их нужно избегать (например, зависание на Python 2.5 без itertools.product и т. Д.), Его, конечно, можно полностью закодировать в "base Питон ", когда нужно.
Попытка «вытащить все остановки» для скорости, может быть что-то вроде:
def odo(*names_and_valuelists):
aux = [[vl, 0] for n, vl in names_and_valuelists]
if any(len(vl)==0 for vl, _ in aux):
return
while True:
yield tuple(vl[i] for vl, i in aux)
for vlandi in reversed(aux):
if vlandi[1] == len(vlandi[0])-1:
vlandi[1] = 0
else:
vlandi[1] += 1
break
else:
return
хотя незначительные изменения могут все же ускорить его (требуется тщательное профилирование с реалистичными данными выборки!).
Вот ваш пример использования:
def main():
data = [
('Col1', 'value11 value12 value13'.split()),
('Col2', 'value21 value22'.split()),
('Col3', 'value31 value32 value33'.split()),
]
for tup in odo(data[0], data[1]): print tup
print
for tup in odo(data[1], data[2]): print tup
print
for i, tup in enumerate(odo(*data)):
print tup
if i>5: break
if __name__ == '__main__':
main()
который выдает результаты:
('value11', 'value21')
('value11', 'value22')
('value12', 'value21')
('value12', 'value22')
('value13', 'value21')
('value13', 'value22')
('value21', 'value31')
('value21', 'value32')
('value21', 'value33')
('value22', 'value31')
('value22', 'value32')
('value22', 'value33')
('value11', 'value21', 'value31')
('value11', 'value21', 'value32')
('value11', 'value21', 'value33')
('value11', 'value22', 'value31')
('value11', 'value22', 'value32')
('value11', 'value22', 'value33')
('value12', 'value21', 'value31')