鱼C论坛

 找回密码
 立即注册
查看: 911|回复: 0

[技术交流] 生成前n个正整数的置换: With/without numpy

[复制链接]
发表于 2021-11-28 22:02:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我写了两段代码,用于返回前 n 个自然数的置换全体:例如当 n = 2 时, 返回 [1,2], [2,1]; n = 3 时, 返回 [1, 2, 3], [1, 3, 2], [2, 1, 3],  [2, 3, 1],  [3, 1, 2],  [3, 2, 1]. 数学上采用同一个原理,区别是一个用numpy的数据结构和方法,另一个用 list.

两段代码如下:

用 numpy 的:
# permutationGenerator

# Author: Xing Gu
# Date: 2021/11/23

def permutation(n):
    """For a positive integer n, returns all the permutations of n as a generator, each permutation being a list of n
    integers. """
    # Manually yield permutation(n) for n=1,2,3.

    import numpy as np

    if n == 0:
        yield np.arange(0, dtype=int)
    elif n == 1:
        yield np.arange(1,2,  dtype=int)
    elif n == 2:
        for item in np.array([[1, 2], [2, 1]], dtype=int):
            yield item
    elif n == 3:
        for item in np.array([[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]], dtype=int):
            yield item
    else:
        # Recursively yield permutation(n) for n>3, the recursion step length being 3.
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue
                for k in range(n):
                    if j == k or i == k:
                        continue
                    im123 = np.array([i + 1, j + 1, k + 1])
                    # the image of 1,2,3 of the permutation sorted in ascending order
                    im123Sorted = np.sort(im123)
                    # To obtain im4plus, first acquire the permutation of n-3, and then change the values to skip the 
                    # images of 1,2,3.
                    # the image of 4,..., n of the permutation
                    im4PlusSorted = np.arange(1, n - 2) + np.concatenate((np.zeros(im123Sorted[0] - 1), \
                                                    np.ones(im123Sorted[1] - im123Sorted[0] - 1), \
                                                    np.ones(im123Sorted[2] - im123Sorted[1] - 1) * 2, \
                                                    np.ones(n - im123Sorted[2]) * 3))
                    for item in permutation(n - 3):
                        im4Plus = im4PlusSorted[item - 1]
                        yield np.concatenate((im123, im4Plus)).astype(int)


if __name__ == '__main__':
    import timeit

    counter = 0
    start = timeit.default_timer()
    for item in permutation(10):
        print(item)
        counter += 1
    stop = timeit.default_timer()
    print('Counter: ', counter)
    print('Time: ', stop - start)

不用 numpy 的:
# permutationGeneratorNieve

# Author: Xing Gu
# Date: 2021/11/23

def permutation(n):
    """For a positive integer n, returns all the permutations of n as a generator, each permutation being a list of n
    integers. """
    # Manually yield permutation(n) for n=1,2,3.
    if n == 0:
        yield []
    elif n == 1:
        yield [1]
    elif n == 2:
        for item in ([[1, 2], [2, 1]]):
            yield item
    elif n == 3:
        for item in ([1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]):
            yield item
    else:
        # Recursively yield permutation(n) for n>3, the recursion step length being 3.
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue
                for k in range(n):
                    if j == k or i == k:
                        continue
                    im123 = [i + 1, j + 1, k + 1]
                    # the image of 1,2,3 of the permutation sorted in ascending order
                    im123Sorted = sorted(im123)
                    # To obtain im4plus, first acquire the permutation of n-3, and then change the values to skip the
                    # images of 1,2,3.
                    # the image of 4,..., n of the permutation
                    for item in permutation(n - 3):
                        im4Plus = []
                        for l in item:
                            if l > im123Sorted[2] - 3:
                                im4Plus.append(l + 3)
                            elif l > im123Sorted[1] - 2:
                                im4Plus.append(l + 2)
                            elif l > im123Sorted[0] - 1:
                                im4Plus.append(l + 1)
                            else:
                                im4Plus.append(l)
                        # Yield a permutation of n.
                        yield im123 + im4Plus


if __name__ == '__main__':
    import timeit

    counter = 0
    start = timeit.default_timer()
    for item in permutation(10):
        print(item)
        counter += 1
    stop = timeit.default_timer()
    print('Counter: ', counter)
    print('Time: ', stop - start)


按理说 numpy相对于python自带的数据结构优化了许多,然而用以上两段代码分别返回前十个正整数的全体置换(3628800个arraies/lists)时,在同一台设备上,前者用时488.1秒,后者29.3秒。用numpy反而慢了十几倍!

问题:(1)当 n 很大时,第一段代码比第二段是否会有更好的表现?(2)在这个任务中是否有更合理的办法使用numpy?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-12 19:08

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表