简体   繁体   English

反转列表中的“行”

[英]Reversing “rows” in a list

I'm making a chess engine in python so I need to optimize everything to run as fast as possible.我正在 python 中制作一个国际象棋引擎,所以我需要优化一切以尽可能快地运行。 When black and white sides are mirrored i need to miror list of scores on squares.当黑白边被镜像时,我需要在正方形上镜像分数列表。

This is a simplified list:这是一个简化的列表:

A = [1,2,3,4,5,6,7,8,9]

Let's imagine this list is a matrix:让我们想象这个列表是一个矩阵:

A = [
1,2,3,
4,5,6,
7,8,9]

What is the fastest way of changing "rows" in this list, so the final result would be:在此列表中更改“行”的最快方法是什么,因此最终结果将是:

A = [
7,8,9,
4,5,6,
1,2,3]

or written in the same line:或写在同一行:

A = [7,8,9,4,5,6,1,2,3]

Real lists have 64 elements and I need to reverse 8 "rows" in them.真实列表有 64 个元素,我需要在其中反转 8 个“行”。 This reversing is done milion times so every improvement is welcome.这种逆转已经完成了数百万次,所以每一次改进都是受欢迎的。 I'm looking for fastest way to do this.我正在寻找最快的方法来做到这一点。 Thank you!谢谢!

Edit:编辑:

I've done it this way, is there any faster way of doing this?我已经这样做了,有没有更快的方法呢?

A = [1,2,3,4,5,6,7,8,9]
A_size = len(A)
row_length = 3

for x in range(0,A_size,row_length):
    A.extend(A[A_size-row_length-x:A_size-x])
del A[0:A_size]
print(A)

Exploring some options:探索一些选项:

numpy should be able to do this efficiently if you use reshape with your list:如果您在列表中使用reshapenumpy应该能够有效地做到这一点:

import numpy
A = [1,2,3,4,5,6,7,8,9]

m = numpy.array(A).reshape(3,3)
print(numpy.flip(m, axis=0))

The convenience method flipud does the same, and as mentioned there, you use indexing to achieve the same: 方便的方法flipud做同样的事情,正如那里提到的,您使用索引来实现相同的目的:

print(numpy.array(A).reshape(3,3)[::-1,...])

The numpy variants turn out to be surprisingly inefficient, perhaps because of the matrix creation overhead. numpy 变体的效率出奇地低,可能是因为矩阵创建开销。 So, a pure-Python alternative to your extend/del loop might be to create a new list from a generator expression:因此,扩展/德尔循环的纯 Python 替代方案可能是从生成器表达式创建一个新列表:

print([e for r in (A[A_size-row_length-x:A_size-x]
    for x in range(0,A_size,row_length)) for e in r])

Another variant makes use of Python's "in-place" slice replacement, and it seems to be the fastest of my variants listed so far:另一个变体使用 Python 的“就地”切片替换,它似乎是我迄今为止列出的最快的变体:

for x in range(0,A_size//2,row_length):
  A[x:x+row_length], A[A_size-row_length-x:A_size-x] = A[A_size-row_length-x:A_size-x], A[x:x+row_length]

However, in my local tests, this last variant is still ~10% slower than your original extend/del variant, and, even more interestingly, this relation seems stable, ie, your original variant is still the fastest of these, when increasing the list size to 50*50.然而,在我的本地测试中,最后一个变体仍然比原来的 extend/del 变体慢约 10%,而且更有趣的是,这种关系似乎很稳定,也就是说,当增加列表大小为 50*50。

As a side-node: If it's an option, I see rather dramatic speed-ups using PyPy .作为一个侧节点:如果它是一个选项,我看到使用PyPy的速度相当显着。 I tried out a full index-wise in-place replacement:我尝试了一个完整的索引就地替换:

    A[0],A[1],A[2],A[3],A[4],A[5],A[6],A[7],A[8],A[9],A[10],A[11],A[12],A[13],A[14],A[15],A[16],A[17],A[18],A[19],A[20],A[21],A[22],A[23],A[24],A[25],A[26],A[27],A[28],A[29],A[30],A[31],A[32],A[33],A[34],A[35],A[36],A[37],A[38],A[39],A[40],A[41],A[42],A[43],A[44],A[45],A[46],A[47],A[48],A[49],A[50],A[51],A[52],A[53],A[54],A[55],A[56],A[57],A[58],A[59],A[60],A[61],A[62],A[63] = A[56],A[57],A[58],A[59],A[60],A[61],A[62],A[63],A[48],A[49],A[50],A[51],A[52],A[53],A[54],A[55],A[40],A[41],A[42],A[43],A[44],A[45],A[46],A[47],A[32],A[33],A[34],A[35],A[36],A[37],A[38],A[39],A[24],A[25],A[26],A[27],A[28],A[29],A[30],A[31],A[16],A[17],A[18],A[19],A[20],A[21],A[22],A[23],A[8],A[9],A[10],A[11],A[12],A[13],A[14],A[15],A[0],A[1],A[2],A[3],A[4],A[5],A[6],A[7]

While this is slightly slower than the slice replacement variant above with the standard Python3, it outperforms the original extend/del loop by a factor of around 2.6 with PyPy.虽然这比上面使用标准 Python3 的切片替换变体稍慢,但它比使用 PyPy 的原始扩展/删除循环的性能高出大约 2.6 倍。

When you want to transform a list and reverse it as being a matrix, you could use the following snippet.当您想要转换列表并将其反转为矩阵时,您可以使用以下代码段。

def chunk(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i + n]


a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

b = list(chunk(a, 3))
b.reverse()
b = sum(b, [])

print(b)

# [7, 8, 9, 4, 5, 6, 1, 2, 3]

When using two-dimensional arrays as a starting point, this task is much easier:当使用二维 arrays 作为起点时,这个任务就容易多了:

a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

a.reverse()    

print(a)

# [[7, 8, 9], [4, 5, 6], [1, 2, 3]]

Try this, which uses a generator to chunk backward from the end of the list to the beginning:试试这个,它使用生成器从列表的末尾向后分块到开头:

from itertools import chain

A = [1,2,3,4,5,6,7,8,9]

def chunk(lst, step):
    start = len(lst)
    for i in range(start, -1, -step):
        yield lst[i-step:i]
    yield lst[0:i]  #any remaning bit

l = list(chain.from_iterable(chunk(A, 3)))

print(l)

Output: Output:

[7, 8, 9, 4, 5, 6, 1, 2, 3]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM