一只名叫tom的猫
这是一个组合问题,最好使用itertools.from itertools import product将每个字典项目扩展为一系列项目:range_items = [[(x, z) for z in range(y + 1)] for x,y in char_counts.items()]#[[('a', 0), ('a', 1)], [('b', 0), ('b', 1), ('b', 2)]]将每个范围中的每个项目与所有其他范围中的每个项目进行笛卡尔积:products = product(*range_items)#[(('a', 0), ('b', 0)), (('a', 0), ('b', 1)),...(('a', 1), ('b', 2))]消除具有 0 个计数器的对,并将剩余的转换为具有字典理解的字典:[{k: v for k, v in pairs if v > 0} for pairs in products]#[{}, {'b': 1}, {'b': 2}, {'a': 1}, {'a': 1, 'b': 1}, {'a': 1, 'b': 2}]
绝地无双
我喜欢DYZ 的回答,但我想知道是否有可能使它成为一个高效的迭代器。DYZ 的range_items空间复杂度类似于 O(n+m),其中n是元素的数量,m是它们的计数之和。product我的解决方案在s 本身上使用range,我很确定它是 O(n)。此外,就术语而言,char_counts基本上是一个多重集,输出与幂集非常相似,所以我猜你会称它为“幂多重集”。顺便说一句,查看collections.Counter,这是标准库中的一个多集对象。import itertoolsdef power_multiset(multiset): """ Generate all sub-multisets of a given multiset, like a powerset. Output is an iterator of dicts. """ elems = [] ranges = [] for elem, count in sorted(multiset.items()): elems.append(elem) ranges.append(range(count+1)) for sub_counts in itertools.product(*ranges): # "if c" filters out items with a 0 count yield {e: c for e, c in zip(elems, sub_counts) if c}>>> char_counts = {"a": 1, "b": 2}>>> list(power_multiset(char_counts))[{}, {'b': 1}, {'b': 2}, {'a': 1}, {'a': 1, 'b': 1}, {'a': 1, 'b': 2}]