itertools.combinations 是一个非常强大且高效的工具,用于获取一个可迭代对象(如列表、元组、字符串等)中指定长度的所有唯一组合。

核心概念
组合 的数学定义是:从一组物品中选取一部分,不考虑顺序,从 A, B, C 中选取 2 个,组合有 (A, B), (A, C), (B, C)。(B, A) 和 (A, B) 被视为同一个组合,因此只出现一次。
这与 排列 不同,排列是考虑顺序的。(A, B) 和 (B, A) 是两种不同的排列。
itertools.combinations 正是用来生成这些组合的。
函数签名
itertools.combinations(iterable, r)
iterable: 一个可迭代对象,例如列表、元组、字符串等。r: 一个整数,表示每个组合中元素的个数。
返回值:

- 返回一个迭代器,这个迭代器会产生
r长度的元组,这些元组是iterable的所有可能组合。
基本使用示例
让我们从几个简单的例子开始。
示例 1:从列表中选取 2 个元素
import itertools
data = ['A', 'B', 'C', 'D']
r = 2
# 创建一个组合迭代器
combinations_iterator = itertools.combinations(data, r)
# 迭代器不能直接打印,需要遍历它
print(f"从 {data} 中选取 {r} 个元素的所有组合:")
for combo in combinations_iterator:
print(combo)
# 输出结果:
# 从 ['A', 'B', 'C', 'D'] 中选取 2 个元素的所有组合:
# ('A', 'B')
# ('A', 'C')
# ('A', 'D')
# ('B', 'C')
# ('B', 'D')
# ('C', 'D')
示例 2:从字符串中选取 3 个字符
字符串本身也是一个可迭代对象,其中每个字符都是一个元素。
import itertools
word = "PQRS"
r = 3
combinations_iterator = itertools.combinations(word, r)
print(f"从字符串 '{word}' 中选取 {r} 个字符的所有组合:")
# 为了方便查看,我们可以将结果转换为列表
print(list(combinations_iterator))
# 输出结果:
# 从字符串 'PQRS' 中选取 3 个字符的所有组合:
# [('P', 'Q', 'R'), ('P', 'Q', 'S'), ('P', 'R', 'S'), ('Q', 'R', 'S')]
示例 3:从数字列表中选取 2 个数字
import itertools
numbers = [10, 20, 30]
r = 2
combinations_iterator = itertools.combinations(numbers, r)
print(f"从 {numbers} 中选取 {r} 个数字的所有组合:")
print(list(combinations_iterator))
# 输出结果:
# 从 [10, 20, 30] 中选取 2 个数字的所有组合:
# [(10, 20), (10, 30), (20, 30)]
重要特性
a) 唯一性
itertools.combinations 不会重复使用 iterable 中的同一个元素,每个元素在一个组合中只能出现一次。
import itertools
data = ['A', 'A', 'B'] # 注意列表中有重复元素 'A'
# 即使输入有重复元素,itertools.combinations 也会根据位置来区分
# 第一个 'A' 和第二个 'A' 是不同的元素
combinations_iterator = itertools.combinations(data, 2)
print(list(combinations_iterator))
# 输出结果:
# [('A', 'A'), ('A', 'B'), ('A', 'B')]
# 解释:
# 1. (第一个'A', 第二个'A')
# 2. (第一个'A', 'B')
# 3. (第二个'A', 'B')
b) 排序性
生成的组合是按照输入 iterable 中元素的原始顺序进行排序的,组合内部的元素顺序也遵循原始顺序,如果 iterable 是 ['C', 'A', 'B'],你不会得到 ('A', 'C') 这样的组合。

c) 迭代器而非列表
itertools.combinations 返回的是一个迭代器,这意味着:
- 节省内存:特别是当
iterable很大时,它不会一次性在内存中生成所有组合,而是按需生成。 - 只能遍历一次:迭代器在遍历完后就会耗尽,不能再次使用。
import itertools
data = [1, 2, 3]
combo_iter = itertools.combinations(data, 2)
print("第一次遍历:")
print(list(combo_iter)) # [ (1, 2), (1, 3), (2, 3) ]
print("\n第二次遍历:")
print(list(combo_iter)) # []
与其他 itertools 函数的区别
理解 combinations 与其他相关函数的区别非常重要。
| 函数名 | 功能 | 关键区别 | 示例 (从 'ABC' 选2个) |
|---|---|---|---|
combinations(iterable, r) |
组合,不考虑顺序,元素不重复。 | 核心:顺序不重要 | ('A', 'B'), ('A', 'C'), ('B', 'C') |
permutations(iterable, r) |
排列,考虑顺序,元素不重复。 | 核心:顺序重要 | ('A', 'B'), ('B', 'A'), ('A', 'C'), ('C', 'A'), ('B', 'C'), ('C', 'B') |
combinations_with_replacement(iterable, r) |
组合,不考虑顺序,元素可重复。 | 核心:元素可重复 | ('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C') |
combinations vs. permutations 示例
import itertools
data = 'ABC'
r = 2
print("--- combinations (组合) ---")
print(list(itertools.combinations(data, r)))
# 输出: [('A', 'B'), ('A', 'C'), ('B', 'C')]
print("\n--- permutations (排列) ---")
print(list(itertools.permutations(data, r)))
# 输出: [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]
实际应用场景
itertools.combinations 在很多场景下都非常有用,尤其是在需要穷举可能性时。
场景 1:生成密码组合(简单版)
假设你知道一个密码是由 ['a', 'b', 'c', 'd'] 中的 3 个不同字母组成的,你想列出所有可能性。
import itertools
chars = ['a', 'b', 'c', 'd']
length = 3
# 注意:这会生成所有可能的3字母组合,但密码可能是排列,所以还需要进一步处理
# 这里只演示 combinations 的用法
all_combinations = itertools.combinations(chars, length)
# 将元组组合成字符串
passwords = [''.join(p) for p in all_combinations]
print(f"所有可能的 {length} 字母组合:")
print(passwords)
# 输出: ['abc', 'abd', 'acd', 'bcd']
场景 2:找出列表中所有可能的二元组
假设你有一个列表 [1, 2, 3, 4],你想找出所有可能的数对(不重复)来进行某种计算或比较。
import itertools
numbers = [1, 2, 3, 4]
# 找出所有可能的比赛队伍对阵(不考虑主客场)
all_pairings = itertools.combinations(numbers, 2)
print("所有可能的队伍对阵:")
for pairing in all_pairings:
print(f"队伍 {pairing[0]} vs 队伍 {pairing[1]}")
# 输出:
# 队伍 1 vs 队伍 2
# 队伍 1 vs 队伍 3
# 队伍 1 vs 队伍 4
# 队伍 2 vs 队伍 3
# 队伍 2 vs 队伍 4
# 队伍 3 vs 队伍 4
场景 3:数据采样与测试
在机器学习中,你可能需要从数据集中创建不同的训练/验证集组合来进行交叉验证。
import itertools
features = ['feature_1', 'feature_2', 'feature_3', 'feature_4']
num_features_to_select = 2
# 选择两个特征进行模型训练
feature_sets = itertools.combinations(features, num_features_to_select)
print("要尝试的特征组合:")
print(list(feature_sets))
# 输出: [('feature_1', 'feature_2'), ('feature_1', 'feature_3'), ...]
itertools.combinations(iterable, r)是 Python 标准库中用于生成无序组合的利器。- 它返回一个迭代器,按需生成组合,内存效率高。
- 组合中的元素不重复,且顺序不重要。
- 当你需要从一组事物中选取一部分,且不关心它们的选取顺序时,
itertools.combinations是你的首选。
