簡體   English   中英

反轉列表中的“行”

[英]Reversing “rows” in a list

我正在 python 中制作一個國際象棋引擎,所以我需要優化一切以盡可能快地運行。 當黑白邊被鏡像時,我需要在正方形上鏡像分數列表。

這是一個簡化的列表:

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

讓我們想象這個列表是一個矩陣:

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

在此列表中更改“行”的最快方法是什么,因此最終結果將是:

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

或寫在同一行:

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

真實列表有 64 個元素,我需要在其中反轉 8 個“行”。 這種逆轉已經完成了數百萬次,所以每一次改進都是受歡迎的。 我正在尋找最快的方法來做到這一點。 謝謝!

編輯:

我已經這樣做了,有沒有更快的方法呢?

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)

探索一些選項:

如果您在列表中使用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))

方便的方法flipud做同樣的事情,正如那里提到的,您使用索引來實現相同的目的:

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

numpy 變體的效率出奇地低,可能是因為矩陣創建開銷。 因此,擴展/德爾循環的純 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])

另一個變體使用 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]

然而,在我的本地測試中,最后一個變體仍然比原來的 extend/del 變體慢約 10%,而且更有趣的是,這種關系似乎很穩定,也就是說,當增加列表大小為 50*50。

作為一個側節點:如果它是一個選項,我看到使用PyPy的速度相當顯着。 我嘗試了一個完整的索引就地替換:

    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]

雖然這比上面使用標准 Python3 的切片替換變體稍慢,但它比使用 PyPy 的原始擴展/刪除循環的性能高出大約 2.6 倍。

當您想要轉換列表並將其反轉為矩陣時,您可以使用以下代碼段。

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]

當使用二維 arrays 作為起點時,這個任務就容易多了:

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

a.reverse()    

print(a)

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

試試這個,它使用生成器從列表的末尾向后分塊到開頭:

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:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM