两列表生成全排列:允许多对一映射及空分配(第二轮)
生成满足多对多有序分配的排列组合
需求概述
需基于两个列表生成所有符合以下规则的映射组合:
- 允许多个
number分配给同一个name,也允许部分或全部number不分配 - 同一
name下的number列表顺序有区分度:[1, 2]与[2, 1]视为不同组合
示例输入
names = ['a', 'b'] numbers = [1, 2]
示例输出
共生成11种符合要求的组合:
1. {'a': [], 'b': []} 2. {'a': [1], 'b': []} 3. {'a': [], 'b': [1]} 4. {'a': [2], 'b': []} 5. {'a': [], 'b': [2]} 6. {'a': [1, 2], 'b': []} 7. {'a': [1], 'b': [2]} 8. {'a': [], 'b': [1, 2]} 9. {'a': [2, 1], 'b': []} 10. {'a': [2], 'b': [1]} 11. {'a': [], 'b': [2, 1]}
实现代码
使用Python的itertools库实现,直接生成所有符合要求的组合:
import itertools def generate_all_assignments(names, numbers): name_count = len(names) num_count = len(numbers) all_assignments = [] # 添加空分配的情况 empty_map = {name: [] for name in names} all_assignments.append(empty_map) # 遍历所有可能的分配数量(1到全部number) for assign_count in range(1, num_count + 1): # 生成当前分配数量下的所有排列(保证顺序区分) for perm in itertools.permutations(numbers, assign_count): # 生成所有分割方式:将排列分割为对应name数量的子序列 # 分割点为name_count-1个非递减的位置,范围0到assign_count for splits in itertools.combinations_with_replacement(range(assign_count + 1), name_count - 1): split_points = [0] + list(splits) + [assign_count] current_assignment = {} # 按分割点为每个name分配对应子序列 for idx in range(name_count): start = split_points[idx] end = split_points[idx + 1] current_assignment[names[idx]] = list(perm[start:end]) all_assignments.append(current_assignment) return all_assignments # 测试示例 if __name__ == "__main__": names = ['a', 'b'] numbers = [1, 2] assignments = generate_all_assignments(names, numbers) for idx, ass in enumerate(assignments, 1): print(f"{idx}. {ass}")
代码说明
- 空分配处理:首先添加所有
name对应空列表的情况 - 排列生成:对每个可能的分配数量
assign_count,生成numbers中选assign_count个元素的所有排列,保证顺序不同的情况被区分 - 分割逻辑:通过组合生成分割点,将排列分割为对应
name数量的子序列,支持同一个name分配多个number、部分name分配空序列的场景 - 结果收集:将所有合法的映射组合收集到列表中返回
内容的提问来源于stack exchange,提问作者Seminko
相关产品推荐
相关产品推荐

