一尘不染

在Python中生成循环移位/缩小的拉丁方

algorithm

只是想知道在Python中生成列表的所有循环移位的最有效方法是什么。在任一方向上。例如,给定一个list [1, 2, 3, 4],我想生成其中一个:

[[1, 2, 3, 4],
 [4, 1, 2, 3],
 [3, 4, 1, 2],
 [2, 3, 4, 1]]

通过将最后一个元素移到最前面来生成下一个排列,或者:

[[1, 2, 3, 4],
 [2, 3, 4, 1],
 [3, 4, 1, 2],
 [4, 1, 2, 3]]

下一个排列是通过将第一个元素移到后面来生成的。

第二种情况对我来说稍微有点有趣,因为它导致减小的拉丁方(第一种情况也给出了一个拉丁方,只是没有减小),这就是我正在尝试进行实验性块设计的方法。实际上,它们与第一种情况并没有什么不同,因为它们只是彼此重新排序,但是顺序仍然很重要。

我对第一种情况的当前实现是:

def gen_latin_square(mylist):
    tmplist = mylist[:]
    latin_square = []
    for i in range(len(mylist)):
        latin_square.append(tmplist[:])
        tmplist = [tmplist.pop()] + tmplist
    return latin_square

对于第二种情况:

def gen_latin_square(mylist):
    tmplist = mylist[:]
    latin_square = []
    for i in range(len(mylist)):
        latin_square.append(tmplist[:])
        tmplist = tmplist[1:] + [tmplist[0]]
    return latin_square

第一种情况似乎对我来说应该是相当有效的,因为它使用pop(),但是在第二种情况下您不能这样做,所以我想听听有关如何更有效地执行此操作的想法。也许有些东西itertools会有所帮助?也许第二种情况是双头队列?


阅读 301

收藏
2020-07-28

共1个答案

一尘不染

对于第一部分,最简洁的方法可能是

a = [1, 2, 3, 4]
n = len(a)
[[a[i - j] for i in range(n)] for j in range(n)]
# [[1, 2, 3, 4], [4, 1, 2, 3], [3, 4, 1, 2], [2, 3, 4, 1]]

第二部分

[[a[i - j] for i in range(n)] for j in range(n, 0, -1)]
# [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]

尽管我没有做任何计时,但它们也应该比您的代码更有效。

2020-07-28