我有三个清单:
a = [0,1,2]
b = [3,4,5]
c = [aab, abb, aaa]
如何创建所有三元素组合?列表c
中的序列告诉您哪个列表可用于为给定输出序列中的给定位置选择数字
例如(伪代码):
for i=0 in range(len(c)):
print: [0,1,3]
[0,1,4]
...
[0,2,5]
...
[1,2,4]
[1,2,5]
其余的i
索引也是如此。不能重复单个子列表中的值的情况。
我将非常感谢任何提示。
答案 0 :(得分:3)
此生成器功能将处理' ab'如果a
和b
列表不相交,则输出列表将不包含重复项目的模板字符串,其中包含a' s和b' s我们使用itertools.combinations
生成所需订单的组合,并使用a
合并b
和itertools.product
组合。我们通过将每个a
和b
组合转换为迭代器并通过字典从正确的迭代器中选择,以正确的顺序获取它们。
from itertools import combinations, product
def groups(a, b, c):
for pat in c:
acombo = combinations(a, pat.count('a'))
bcombo = combinations(b, pat.count('b'))
for ta, tb in product(acombo, bcombo):
d = {'a': iter(ta), 'b': iter(tb)}
yield [next(d[k]) for k in pat]
# tests
a = [0,1,2]
b = [3,4,5]
templates = ['aab', 'abb', 'aaa'], ['aba'], ['bab']
for c in templates:
print('c', c)
for i, t in enumerate(groups(a, b, c), 1):
print(i, t)
print()
<强>输出强>
c ['aab', 'abb', 'aaa']
1 [0, 1, 3]
2 [0, 1, 4]
3 [0, 1, 5]
4 [0, 2, 3]
5 [0, 2, 4]
6 [0, 2, 5]
7 [1, 2, 3]
8 [1, 2, 4]
9 [1, 2, 5]
10 [0, 3, 4]
11 [0, 3, 5]
12 [0, 4, 5]
13 [1, 3, 4]
14 [1, 3, 5]
15 [1, 4, 5]
16 [2, 3, 4]
17 [2, 3, 5]
18 [2, 4, 5]
19 [0, 1, 2]
c ['aba']
1 [0, 3, 1]
2 [0, 4, 1]
3 [0, 5, 1]
4 [0, 3, 2]
5 [0, 4, 2]
6 [0, 5, 2]
7 [1, 3, 2]
8 [1, 4, 2]
9 [1, 5, 2]
c ['bab']
1 [3, 0, 4]
2 [3, 0, 5]
3 [4, 0, 5]
4 [3, 1, 4]
5 [3, 1, 5]
6 [4, 1, 5]
7 [3, 2, 4]
8 [3, 2, 5]
9 [4, 2, 5]
我应该提一下,即使combinations
返回迭代器,而product
也很乐意将迭代器作为参数,它必须从迭代器生成列表,因为它必须多次遍历迭代器内容。因此,如果组合的数量很大,则会消耗相当多的RAM。
如果你想要排列而不是组合,这很容易。我们只需拨打itertools.permutations
而不是itertools.combinations
。
from itertools import permutations, product
def groups(a, b, c):
for pat in c:
acombo = permutations(a, pat.count('a'))
bcombo = permutations(b, pat.count('b'))
for ta, tb in product(acombo, bcombo):
d = {'a': iter(ta), 'b': iter(tb)}
yield [next(d[k]) for k in pat]
# tests
a = [0,1,2]
b = [3,4,5]
templates = ['aaa'], ['abb']
for c in templates:
print('c', c)
for i, t in enumerate(groups(a, b, c), 1):
print(i, t)
print()
<强>输出强>
c ['aaa']
1 [0, 1, 2]
2 [0, 2, 1]
3 [1, 0, 2]
4 [1, 2, 0]
5 [2, 0, 1]
6 [2, 1, 0]
c ['abb']
1 [0, 3, 4]
2 [0, 3, 5]
3 [0, 4, 3]
4 [0, 4, 5]
5 [0, 5, 3]
6 [0, 5, 4]
7 [1, 3, 4]
8 [1, 3, 5]
9 [1, 4, 3]
10 [1, 4, 5]
11 [1, 5, 3]
12 [1, 5, 4]
13 [2, 3, 4]
14 [2, 3, 5]
15 [2, 4, 3]
16 [2, 4, 5]
17 [2, 5, 3]
18 [2, 5, 4]
最后,这是一个处理任意数量的列表和任意长度的模板字符串的版本。它每次调用只接受一个模板字符串,但这不应该是一个问题。您还可以选择是否要通过可选关键字arg生成排列或组合。
from itertools import permutations, combinations, product
def groups(sources, template, mode='P'):
func = permutations if mode == 'P' else combinations
keys = sources.keys()
combos = [func(sources[k], template.count(k)) for k in keys]
for t in product(*combos):
d = {k: iter(v) for k, v in zip(keys, t)}
yield [next(d[k]) for k in template]
# tests
sources = {
'a': [0, 1, 2],
'b': [3, 4, 5],
'c': [6, 7, 8],
}
templates = 'aa', 'abc', 'abba', 'cab'
for template in templates:
print('\ntemplate', template)
for i, t in enumerate(groups(sources, template, mode='C'), 1):
print(i, t)
<强>输出强>
template aa
1 [0, 1]
2 [0, 2]
3 [1, 2]
template abc
1 [0, 3, 6]
2 [0, 3, 7]
3 [0, 3, 8]
4 [0, 4, 6]
5 [0, 4, 7]
6 [0, 4, 8]
7 [0, 5, 6]
8 [0, 5, 7]
9 [0, 5, 8]
10 [1, 3, 6]
11 [1, 3, 7]
12 [1, 3, 8]
13 [1, 4, 6]
14 [1, 4, 7]
15 [1, 4, 8]
16 [1, 5, 6]
17 [1, 5, 7]
18 [1, 5, 8]
19 [2, 3, 6]
20 [2, 3, 7]
21 [2, 3, 8]
22 [2, 4, 6]
23 [2, 4, 7]
24 [2, 4, 8]
25 [2, 5, 6]
26 [2, 5, 7]
27 [2, 5, 8]
template abba
1 [0, 3, 4, 1]
2 [0, 3, 5, 1]
3 [0, 4, 5, 1]
4 [0, 3, 4, 2]
5 [0, 3, 5, 2]
6 [0, 4, 5, 2]
7 [1, 3, 4, 2]
8 [1, 3, 5, 2]
9 [1, 4, 5, 2]
template cab
1 [6, 0, 3]
2 [7, 0, 3]
3 [8, 0, 3]
4 [6, 0, 4]
5 [7, 0, 4]
6 [8, 0, 4]
7 [6, 0, 5]
8 [7, 0, 5]
9 [8, 0, 5]
10 [6, 1, 3]
11 [7, 1, 3]
12 [8, 1, 3]
13 [6, 1, 4]
14 [7, 1, 4]
15 [8, 1, 4]
16 [6, 1, 5]
17 [7, 1, 5]
18 [8, 1, 5]
19 [6, 2, 3]
20 [7, 2, 3]
21 [8, 2, 3]
22 [6, 2, 4]
23 [7, 2, 4]
24 [8, 2, 4]
25 [6, 2, 5]
26 [7, 2, 5]
27 [8, 2, 5]
答案 1 :(得分:2)
from itertools import product, chain
setups = ['aab', 'abb', 'aaa']
sources = {
'a': [0,1,2],
'b': [3,4,5]
}
combinations = (product(*map(sources.get, setup)) for setup in setups)
combinations
是一个嵌套的惰性迭代器(即没有任何内容存储在内存中并进行计算)。如果你想得到列表的迭代器
combinations = map(list, (product(*map(sources.get, setup)) for setup in setups))
或者您可能想要展平结果:
combinations = chain.from_iterable(product(*map(sources.get, setup)) for setup in setups)
答案 2 :(得分:1)
将列表放在字典中,以便您可以使用字符串访问它们 使用每个序列中的字符来确定要使用的列表 使用itertools.product获取组合。
import itertools, collections
from pprint import pprint
d = {'a':[0,1,2], 'b':[3,4,5]}
c = ['aab', 'abb', 'aaa']
def f(t):
t = collections.Counter(t)
return max(t.values()) < 2
for seq in c:
data = (d[char] for char in seq)
print(f'sequence: {seq}')
pprint(list(filter(f, itertools.product(*data))))
print('***************************')
序列'abb'
的结果:
sequence: abb
[(0, 3, 4),
(0, 3, 5),
(0, 4, 3),
(0, 4, 5),
(0, 5, 3),
(0, 5, 4),
(1, 3, 4),
(1, 3, 5),
(1, 4, 3),
(1, 4, 5),
(1, 5, 3),
(1, 5, 4),
(2, 3, 4),
(2, 3, 5),
(2, 4, 3),
(2, 4, 5),
(2, 5, 3),
(2, 5, 4)]
编辑以使用重复
过滤掉元组我喜欢可以与map一起使用的可调用dict的想法。它可以在这里使用。
class CallDict(dict):
def __call__(self, key):
return self[key] #self.get(key)
e = CallDict([('a',[0,1,2]), ('b',[3,4,5])])
for seq in c:
data = map(e, seq)
print(f'sequence: {seq}')
for thing in filter(f, itertools.product(*data)):
print(thing)
print('***************************')
我无法自拔,这是@ PM2Ring solution/answer的通用版本。不是过滤掉不需要的物品,而是首先不产生它们。
d = {'a':[0,1,2], 'b':[3,4,5]}
c = ['aab', 'abb', 'aaa', 'aba']
def g(d, c):
for seq in c:
print(f'sequence: {seq}')
counts = collections.Counter(seq)
## data = (itertools.combinations(d[key],r) for key, r in counts.items())
data = (itertools.permutations(d[key],r) for key, r in counts.items())
for thing in itertools.product(*data):
q = {key:iter(other) for key, other in zip(counts, thing)}
yield [next(q[k]) for k in seq]
for t in g(d, c):
print(t)
答案 3 :(得分:1)
如果我理解正确,您可以通过字典簿记来实现目标,例如"a"
这样的字符与变量名a
的对应关系。
from collections import defaultdict
a = [0,1,2]
b = [3,4,5]
c = ["aab", "abb", "aaa"]
d = {"a": a, "b": b}
d2 = defaultdict(list)
for seq in c:
l = []
for idx, v in enumerate(seq):
l.append(d[v][idx])
print(l)
d2[seq].append(l)
# Out:
#[0, 1, 5]
#[0, 4, 5]
#[0, 1, 2]
print(d2)
# defaultdict(<class 'list'>, {'aab': [[0, 1, 5]], 'abb': [[0, 4, 5]], 'aaa': [[0, 1, 2]]})
答案 4 :(得分:0)
您似乎正在寻找以编程方式调用itertools.product
from itertools import product
d = {'a': [0,1,2],
'b': [3,4,5]}
c = ['aab', 'abb', 'aaa']
for s in c:
print(list(product(*[d[x] for x in s])))