我有一个数字列表,我想从中组合.如果我有清单:
t = [2,2,2,2,4]
c = list(itertools.combinations(t, 4))
Run Code Online (Sandbox Code Playgroud)
结果是:
(2, 2, 2, 2)
(2, 2, 2, 4)
(2, 2, 2, 4)
(2, 2, 2, 4)
(2, 2, 2, 4)
Run Code Online (Sandbox Code Playgroud)
但我想得到:
(2, 2, 2, 2)
(2, 2, 2, 4)
Run Code Online (Sandbox Code Playgroud)
是否有可能消除重复,除了制作新的列表并通过第一个列表?
我知道这已经晚了但我想补充一点.
set(itertools.combinations(t, 4))在大多数情况下会做得很好,但它仍然在内部迭代所有重复组合,因此它可能在计算上很重.如果没有很多实际的唯一组合,情况尤其如此.
这个只迭代唯一的组合:
from itertools import chain,repeat,islice,count
from collections import Counter
def combinations_without_repetition(r, iterable=None, values=None, counts=None):
if iterable:
values, counts = zip(*Counter(iterable).items())
f = lambda i,c: chain.from_iterable(map(repeat, i, c))
n = len(counts)
indices = list(islice(f(count(),counts), r))
if len(indices) < r:
return
while True:
yield tuple(values[i] for i in indices)
for i,j in zip(reversed(range(r)), f(reversed(range(n)), reversed(counts))):
if indices[i] != j:
break
else:
return
j = indices[i]+1
for i,j in zip(range(i,r), f(count(j), islice(counts, j, None))):
indices[i] = j
Run Code Online (Sandbox Code Playgroud)
用法:
>>> t = [2,2,2,2,4]
# elements in t must be hashable
>>> list(combinations_without_repetition(4, iterable=t))
[(2, 2, 2, 2), (2, 2, 2, 4)]
# You can pass values and counts separately. For this usage, values don't need to be hashable
# Say you have ['a','b','b','c','c','c'], then since there is 1 of 'a', 2 of 'b', and 3 of 'c', you can do as follows:
>>> list(combinations_without_repetition(3, values=['a','b','c'], counts=[1,2,3]))
[('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'c'), ('b', 'b', 'c'), ('b', 'c', 'c'), ('c', 'c', 'c')]
# combinations_without_repetition() is a generator (and thus an iterator)
# so you can iterate it
>>> for comb in combinations_without_repetition(4, t):
... print(sum(comb))
...
8 # 2+2+2+2
10 # 2+2+2+4
Run Code Online (Sandbox Code Playgroud)
注意,它itertools.combinations()是用C实现的,这意味着在大多数情况下它比我的python脚本快得多.set(itertools.combinations())仅当有多个重复组合而不是唯一组合时,此代码才比方法更好.
现在可以使用more-itertools包来完成此操作,从版本 8.7 开始,该包有一个名为distinct_combinations的函数来实现此目的。
>>> from itertools import combinations
>>> t = [2,2,2,2,4]
>>> set(combinations(t, 4))
{(2, 2, 2, 2), (2, 2, 2, 4)}
>>> from more_itertools import distinct_combinations
>>> t = [2,2,2,2,4]
>>> list(distinct_combinations(t,4))
(2, 2, 2, 2), (2, 2, 2, 4)]
Run Code Online (Sandbox Code Playgroud)
据我所知,我非常有限的测试性能与@hahho 编写的函数类似
正如Donkey Kong指出的那样,您可以通过将列表转换为集合来获得列表中的唯一值:
t = [2,2,2,2,4]
c = list(itertools.combinations(t, 4))
unq = set(c)
print(unq)
Run Code Online (Sandbox Code Playgroud)
结果将是:
{(2, 2, 2, 4), (2, 2, 2, 2)}
Run Code Online (Sandbox Code Playgroud)
如果要将其用作列表,可以通过执行以下操作将其转换回:
result = list(unq)
Run Code Online (Sandbox Code Playgroud)
另一种更清洁,更全面的方式将是:
t = [2,2,2,2,4]
c = set(itertools.combinations(t, 4))
Run Code Online (Sandbox Code Playgroud)
从技术上讲,itertools.combinations如果您阅读链接页面中的描述,那么您获得的内容实际上并不重复,只是如何工作:
itertools.combinations(iterable, r)返回输入iterable中元素的r个子序列.
组合以字典排序顺序发出.因此,如果对输入iterable进行排序,则将按排序顺序生成组合元组.
元素根据其位置而不是其价值被视为唯一元素.因此,如果输入元素是唯一的,则每个组合中将不存在重复值.
DEMO:
>>> import itertools as it
>>> list(it.combinations([1,2,3,4,5], 4))
[(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 4, 5), (1, 3, 4, 5), (2, 3, 4, 5)]
Run Code Online (Sandbox Code Playgroud)
因此,正如在上一个答案中发布的那样,set()将为您提供所需的唯一值:
>>> set(it.combinations(t, 4))
{(2, 2, 2, 4), (2, 2, 2, 2)}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10412 次 |
| 最近记录: |