直接调用 itertools.combinations(iterable, r) 返回迭代器,需转 list 或遍历才能看到结果;它按索引生成 tuple 组合,不 dedup、不报错、不自动展开,与数学组合 C(n,r) 对应的前提是元素互异且去重。

combinations 函数怎么用才不漏掉组合
直接调用 itertools.combinations(iterable, r) 就行,但它只返回迭代器,不自动展开——很多人写了代码却看不到结果,是因为忘了转成 list 或遍历。
- 必须手动消费:比如
list(combinations([1,2,3], 2))得到[(1, 2), (1, 3), (2, 3)],否则打印对象本身只显示<itertools.combinations object at></itertools.combinations> - 输入必须是可迭代对象,但内部会转成 tuple 处理;如果传入生成器(如
(x for x in range(3))),第一次遍历后就空了,后续再调用会得空结果 -
r超出长度时不会报错,而是安静地返回空迭代器:list(combinations([1], 2))是[],不是异常
为什么结果是 tuple 而不是 list
因为 combinations 内部用 tuple 缓存每次生成的组合项,这是性能权衡:tuple 不可变,避免意外修改导致后续迭代错乱,也省去 list 的内存分配开销。
- 如果你需要 list 形式,得自己转:
[list(c) for c in combinations([1,2,3], 2)] - 别试图在 lambda 里改 tuple 元素——
TypeError: 'tuple' object does not support item assignment会立刻出现 - 对字符串输入,结果是字符 tuple:
combinations('ab', 1)→[('a',), ('b',)],不是['a', 'b']
和数学组合 C(n,r) 的数量对不上?检查输入类型
常见错觉是“我给了 4 个元素,选 2 个,怎么只有 3 组”,其实是输入含重复值或没去重,而 combinations 不做 dedup,它严格按位置取,不是按值。
- 输入
[1, 1, 2]+r=2得到[(1, 1), (1, 2), (1, 2)]—— 三个结果,不是两个,因为索引 0&1、0&2、1&2 都算不同组合 - 要按值去重组合,得先
list(set(your_list)),但注意这会丢顺序;若需保序去重,用dict.fromkeys(...) - 数学公式 C(n,r) 假设 n 个**互异**元素,而 Python 只认索引,不认语义
性能差?别在循环里反复调用 combinations
每次调用 combinations 都新建迭代器对象,如果在内层循环中高频调用(比如模拟回溯),会明显拖慢。更糟的是,有人把整个结果转成 list 后再 len(),其实 math.comb(n, r)(Python 3.8+)直接算数量快得多。
立即学习“Python免费学习笔记(深入)”;
- 要数量不要内容:用
math.comb(len(items), r),比len(list(combinations(items, r)))快几个数量级 - 要全部组合且数据不大(n ≤ 20):没问题;n > 25 就该考虑生成器逐个处理,别全 load 到内存
- 替代方案:如果只是判断某组合是否满足条件,用
any(...)包裹生成器表达式,早停比全生成再过滤强得多










