Python | 排列与组合

本文简要总结在 Python 中实现排列与组合的方法。

Update: 2022 / 11 / 21

总览

在做数据分析的时候,可能会碰到类似于高中所学过的取小球问题。这时候可以使用已有的库 ( itertools, numpy 等 ) 与函数或者自己构造相应的方法来达到目的。

方法

比如,我们要实现 1234 的排列组合,利用高中曾学过的知识,我们可以很容易写出来 1,如下表:

考虑顺序与否元素个数组合
F1(1,), (2,), (3,), (4,)
2(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)
3(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)
T1(1,), (2,), (3,), (4,)
2(1, 2), (1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 3)
3(1, 2, 3), (1, 2, 4), (1, 3, 2), (1, 3, 4), (1, 4, 2), (1, 4, 3), (2, 1, 3), (2, 1, 4), (2, 3, 1), (2, 3, 4), (2, 4, 1), (2, 4, 3), (3, 1, 2), (3, 1, 4), (3, 2, 1), (3, 2, 4), (3, 4, 1), (3, 4, 2), (4, 1, 2), (4, 1, 3), (4, 2, 1), (4, 2, 3), (4, 3, 1), (4, 3, 2)

itertools

itertools 模块下提供了一些用于生成排列组合的工具函数 2


用法

方法含义
product(p, q, … [repeat=1])用序列 pq、…序列中的元素进行排列(元素会重复)。就相当于使用嵌套循环组合。
permutations(p[, r])从序列 p 中取出 r 个元素的组成全排列,组合得到元组作为新迭代器的元素。
combinations(p, r)从序列 p 中取出 r 个元素组成全组合,元素不允许重复,组合得到元组作为新迭代器的元素。
combinations_with_replacement(p, r)从序列 p 中取出 r 个元素组成全组合,元素允许重复,组合得到元组作为新迭代器的元素。

示例

以下面的列表为例,

import itertools

L = [1, 2, 3, 4]

不考虑顺序

comb1 = list(itertools.combinations([1,2,3,4],1))
'''
[(1,), (2,), (3,), (4,)]
'''

comb2 = list(itertools.combinations([1,2,3,4],2))
'''
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
'''

comb3 = list(itertools.combinations([1,2,3,4],3))
'''
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
'''

考虑顺序

comb1 = list(itertools.permutations([1,2,3,4],1))
'''
[(1,), (2,), (3,), (4,)]
'''

comb2 = list(itertools.permutations([1,2,3,4],2))
'''
[(1, 2), (1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 3)]
'''

comb3 = list(itertools.permutations([1,2,3,4],3))
'''
[(1, 2, 3), (1, 2, 4), (1, 3, 2), (1, 3, 4), (1, 4, 2), (1, 4, 3), (2, 1, 3), (2, 1, 4), (2, 3, 1), (2, 3, 4), (2, 4, 1), (2, 4, 3), (3, 1, 2), (3, 1, 4), (3, 2, 1), (3, 2, 4), (3, 4, 1), (3, 4, 2), (4, 1, 2), (4, 1, 3), (4, 2, 1), (4, 2, 3), (4, 3, 1), (4, 3, 2)]
'''

numpy

示例

以下面的列表为例,

import numpy as np
import random

L = [1, 2, 3, 4]

不考虑顺序

elecnt = len(L)
cnt = 2
A = np.product(np.arange(1, elecnt+1))
B = np.product(np.arange(1, elecnt+1-cnt)) * np.product(np.arange(1, 1+cnt))
combcnt = int(A/B)


def combinations(combcnt, elecnt, cnt):
    trials = combcnt
    rslt = []
    while trials > 0:
        sample = sorted(random.sample(list(range(1, 1+elecnt)), cnt))
        if sample in rslt:
            continue
        else:
            if len(rslt) == combcnt:
                break
            else:
                rslt.append(sample)
                trials -= 1
    return sorted(rslt)
#
comb = combinations(combcnt=combcnt, elecnt=elecnt, cnt=cnt)
print(f"self-defined: #{len(comb)}: {comb}")
'''
self-defined: #6: [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
'''

import itertools
comb = list(itertools.combinations(L, 2))
print(f'itertools   : #{len(comb)}: {comb}')
'''
itertools   : #6: [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
'''

利用上文介绍到的 itertools.combinations 的方法,检验自定义函数 combinations 的结果的准确程度。


考虑顺序

参考这里 3

array_L = np.array(L)
cnt = 3

comb = np.unique(np.array(np.meshgrid(array_L, array_L, array_L)).T.reshape(-1, cnt), axis=0)
print(f"\ncomb:\n{comb}")
'''
[[1 1 1]
 [1 2 1]
 [1 3 1]
 [1 4 1]
 [2 1 1]
 [2 2 1]
 ......
 [4 1 4]
 [4 2 4]
 [4 3 4]
 [4 4 4]]
 # shape, (64, 3)
'''


import itertools

comb = list(itertools.product(L, repeat=cnt))
'''
[[1 1 1]
 [1 2 1]
 [1 3 1]
 [1 4 1]
 [2 1 1]
 [2 2 1]
 ......
 [4 1 4]
 [4 2 4]
 [4 3 4]
 [4 4 4]]
 # shape, (64, 3)
'''

利用上文介绍到的 itertools.product 的方法,检验使用 numpy 所得结果的准确程度。


参考链接


  1. 用python实现排列组合 ↩︎

  2. Python的排列组合函数 ↩︎

  3. How to build an array of all combinations of two NumPy arrays? ↩︎

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2023年3月10日
下一篇 2023年3月10日

相关推荐