【发布时间】:2022-10-15 17:15:32
【问题描述】:
问题:
- 我有一个没有重复的元素列表(基本上是一组);
- 我想要一个列表,其中包含长度
L的所有组合,每个元素的重复次数不超过r。
完成此任务的最佳pythonic方法是什么?
可能对this answer 进行一些调整?...
【问题讨论】:
标签: python python-3.x combinatorics
问题:
L 的所有组合,每个元素的重复次数不超过r。
完成此任务的最佳pythonic方法是什么?
可能对this answer 进行一些调整?...
【问题讨论】:
标签: python python-3.x combinatorics
您可以使用itertools.combinations_with_replacement,然后使用collections.Counter 过滤掉重复元素过多的元素。
from itertools import combinations_with_replacement
from collections import Counter
a = ["h","e","l","o","w","r","d"]
L, r = 3, 2
result = []
for combo in combinations_with_replacement(a, L):
tally = Counter(combo)
if max(tally.values()) <= r:
result.append(combo)
print(result)
输出
[('h', 'h', 'e'), ('h', 'h', 'l'), ('h', 'h', 'o'), ('h', 'h', 'w'), ('h', 'h', 'r'), ('h', 'h', 'd'), ('h', 'e', 'e'), ('h', 'e', 'l'), ('h', 'e', 'o'), ('h', 'e', 'w'), ('h', 'e', 'r'), ('h', 'e', 'd'),
('h', 'l', 'l'), ('h', 'l', 'o'), ('h', 'l', 'w'), ('h', 'l', 'r'), ('h', 'l', 'd'), ('h', 'o', 'o'), ('h', 'o', 'w'), ('h', 'o', 'r'), ('h', 'o', 'd'), ('h', 'w', 'w'), ('h', 'w', 'r'), ('h', 'w', 'd'),
('h', 'r', 'r'), ('h', 'r', 'd'), ('h', 'd', 'd'), ('e', 'e', 'l'), ('e', 'e', 'o'), ('e', 'e', 'w'), ('e', 'e', 'r'), ('e', 'e', 'd'), ('e', 'l', 'l'), ('e', 'l', 'o'), ('e', 'l', 'w'), ('e', 'l', 'r'),
('e', 'l', 'd'), ('e', 'o', 'o'), ('e', 'o', 'w'), ('e', 'o', 'r'), ('e', 'o', 'd'), ('e', 'w', 'w'), ('e', 'w', 'r'), ('e', 'w', 'd'), ('e', 'r', 'r'), ('e', 'r', 'd'), ('e', 'd', 'd'), ('l', 'l', 'o'),
('l', 'l', 'w'), ('l', 'l', 'r'), ('l', 'l', 'd'), ('l', 'o', 'o'), ('l', 'o', 'w'), ('l', 'o', 'r'), ('l', 'o', 'd'), ('l', 'w', 'w'), ('l', 'w', 'r'), ('l', 'w', 'd'), ('l', 'r', 'r'), ('l', 'r', 'd'),
('l', 'd', 'd'), ('o', 'o', 'w'), ('o', 'o', 'r'), ('o', 'o', 'd'), ('o', 'w', 'w'), ('o', 'w', 'r'), ('o', 'w', 'd'), ('o', 'r', 'r'), ('o', 'r', 'd'), ('o', 'd', 'd'), ('w', 'w', 'r'), ('w', 'w', 'd'),
('w', 'r', 'r'), ('w', 'r', 'd'), ('w', 'd', 'd'), ('r', 'r', 'd'), ('r', 'd', 'd')]
【讨论】:
这是一个自定义实现,可以避免所有不必要的计算:
def comb(elements, size, repeat):
yield from _comb(elements, size, repeat, ())
def _comb(elements, size, repeat, accum):
if size == 0:
yield accum
return
elem, *rest = elements
min_count = max(size-repeat*len(rest), 1)
max_count = min(size, repeat) + 1
for count in range(min_count, max_count):
new_accum = accum + (elem, ) * count
yield from _comb(rest, size-count, repeat, new_accum)
例子:
>>> list(comb([2,3,4,5], size=7, repeat=3))
[(2, 3, 4, 4, 5, 5, 5), (2, 3, 4, 4, 4, 5, 5), (2, 3, 3, 4, 5, 5, 5), (2, 3, 3, 4, 4, 5, 5), (2, 3, 3, 4, 4, 4, 5), (2, 3, 3, 3, 4, 5, 5), (2, 3, 3, 3, 4, 4, 5), (2, 3, 3, 3, 4, 4, 4), (2, 2, 3, 4, 5, 5, 5), (2, 2, 3, 4, 4, 5, 5), (2, 2, 3, 4, 4, 4, 5), (2, 2, 3, 3, 4, 5, 5), (2, 2, 3, 3, 4, 4, 5), (2, 2, 3, 3, 4, 4, 4), (2, 2, 3, 3, 3, 4, 5), (2, 2, 3, 3, 3, 4, 4), (2, 2, 2, 3, 4, 5, 5), (2, 2, 2, 3, 4, 4, 5), (2, 2, 2, 3, 4, 4, 4), (2, 2, 2, 3, 3, 4, 5), (2, 2, 2, 3, 3, 4, 4), (2, 2, 2, 3, 3, 3, 4)]
如果遇到递归深度问题(如果列表中的元素太多),您当然可以将其转换为迭代变体。
【讨论】:
查看itertools中的combinations_with_replacement()
import itertools
for combination in itertools.combinations_with_replacement(['red', 'green', 'blue', 'yellow'], r=3):
print(combination)
('red', 'red', 'red')
('red', 'red', 'green')
('red', 'red', 'blue')
('red', 'red', 'yellow')
('red', 'green', 'green')
('red', 'green', 'blue')
('red', 'green', 'yellow')
('red', 'blue', 'blue')
('red', 'blue', 'yellow')
('red', 'yellow', 'yellow')
('green', 'green', 'green')
('green', 'green', 'blue')
('green', 'green', 'yellow')
('green', 'blue', 'blue')
('green', 'blue', 'yellow')
('green', 'yellow', 'yellow')
('blue', 'blue', 'blue')
('blue', 'blue', 'yellow')
('blue', 'yellow', 'yellow')
('yellow', 'yellow', 'yellow')
>>>
【讨论】: