簡體   English   中英

Python:從右到左拉鏈的最快方法是什么,是不是內置了?

[英]Python: What's the fastest way to zip right to left, and is there no builtin for this?

給出2個不同長度的序列:

In [931]: a = [1,2,3]
In [932]: b = [4,5,6,7]

這就是我要的

In [933]: c = zip(reversed(a),reversed(b))
In [934]: [x for x in reversed(c)]
Out[934]: [(1, 5), (2, 6), (3, 7)]

但是我不喜歡在所有輸入參數上使用reverse的想法,我也不想重新實現我自己的zip函數。

所以:

  1. 是否有更快/更有效的方法來做到這一點?
  2. 有更簡單的方法嗎?

以下內容比其他發布的解決方案更快更清晰:

s = zip(reversed(a), reversed(b))
s.reverse()                       # in-place

反向內置創建一個迭代器,它們以與前向迭代相同的速度向后循環。 不會產生額外的內存(輸入的完整副本),並且Python eval-loop周圍沒有慢速跳轉(存在於使用指示的其他解決方案中)。

即使您不知道哪個更長,以下內容也會起作用:

>>> zip(a[-len(b):], b[-len(a):])
[(1, 5), (2, 6), (3, 7)]

以下是較小列表的示例:

>>> range(5)[-10:]
[0, 1, 2, 3, 4]

因此,即使切片看起來有點時髦,如果您的負起始值大於列表的長度,它將為您提供整個列表。

我會建議:

>>> a = [1,2,3]
>>> b = [4,5,6,7]
>>> k = min(len(a),len(b))
>>> zip(a[-k:], b[-k:])
[(1, 5), (2, 6), (3, 7)]

在以下解決方案中,不會完成任何輸入列表的副本。

def rzip(a,b):
    m = min(len(a),len(b))
    for i in xrange(m):
        yield a[-m+i],b[-m+i]


for a,b in (([1,2,3,4,5,6,7],[8,9,10]),
            ([1,2,3],[8,9,10]),
            ([1,2,3,4],[1,2,3,4,5,6,7,8,9,10])):
    print list(rzip(a,b))

m是最短列表的長度, -m + 0總是轉換為最短列表的索引0,
-m + 0在最長列表的索引> = 0中進行轉換

結果:

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

盡管功能rzip()不是單行,但我認為它很簡單,我敢打賭它是更快的解決方案

編輯

首先,在上面的函數rzip() (以及下面代碼中的eyquem1)中,我認為通過從左到右從每個列表中的正確位置運行來創建壓縮元素列表也是一個很好的過程。 在下面的代碼中,eyquem1bis是通過預先計算起始位置稍微改進的函數rzip()

但我對Raymond Hettinger聲稱獨家使用zip()和iterator reversed()是更清晰,更快速的解決方案感興趣。 所以我想到從左到右使用其他迭代器會比我的函數rzip()更好,我使用iter()islice()在下面的代碼中編寫函數eyquem2和eyquem3。

我比較了大多數答案中提出的各種解決方案的執行時間。

import random
from time import clock

lima,limb = 20000 , 50000

a = list(range(lima))
b = list(range(limb))
random.shuffle(a)
random.shuffle(b)


A,B,C,D,E,F,G,H,I = [],[],[],[],[],[],[],[],[],

n = 10
for essays in range(100):

    te = clock()
    for rep in range(n):
        k = min(len(a),len(b)) 
        sam1 = list(zip(a[-k:], b[-k:]))
    tref= (clock()-te)/100
    A.append((clock()-te,
              'Sam Hocevar, deducted normal slicing and zip'
              '\nk = min(len(a),len(b))'
              '\nlist(zip(a[-k:], b[-k:]))'))


    te = clock()
    for rep in range(n):
        k = min(len(a),len(b)) 
        sam2 = list(zip(a[len(a)-k:], b[len(b)-k:]))
    tref= (clock()-te)/100
    B.append((clock()-te,
              'Sam Hocevar, exactly normal slicing and zip'
              '\nk = min(len(a),len(b))'
              '\nlist(zip(a[len(a)-k:], b[len(b)-k:]))'))


    te = clock()
    for rep in range(n):
        fj = list(zip(a[-len(b):], b[-len(a):]))
    C.append((clock()-te,
              'F.J. , deducted tricky slicing and zip'
              '\nlist(zip(a[-len(b):], b[-len(a):]))'))


    te = clock()
    for rep in range(n):
        m = min(len(a),len(b))
        sleep = list(zip(a[len(a)-m:],b[len(b)-m:]))
    D.append((clock()-te,
              'sleeplessnerd, exactly normal slicing and zip'
              '\nm = min(len(a),len(b))'
              '\nlist(zip(a[len(a)-m:],b[len(b)-m:]))'))


    te = clock()
    for rep in range(n):
        m = min(len(a),len(b))
        ey1 = [ (a[-m+i],b[-m+i]) for i in range(m) ]
    E.append((clock()-te,
              'eyquem 1, deducted normal slicing and listcomp'
              '\nm = min(len(a),len(b))'
              '\n[ (a[-m+i],b[-m+i]) for i in range(m) ]'))


    te = clock()
    for rep in range(n):
        m = min(len(a),len(b))
        x,y = len(a)-m , len(b)-m
        ey1bis = [ (a[x+i],b[y+i]) for i in range(m)]
    F.append((clock()-te,
              'eyquem 1 improved, exactly normal slicing and listcomp'
              '\nm = min(len(a),len(b)'
              '\nx,y = len(a)-m , len(b)-m'
              '\n[(a[x+i],b[y+i]) for i in range(m)]'))


    te = clock()
    for rep in range(n):
        ita = iter(a)
        itb = iter(b)
        if len(b)>len(a):
            for av in range(len(b)-len(a)):
                itb.__next__()
        else:
            for av in range(len(a)-len(b)):
                itb.__next__()
        ey2 = list(zip(ita,itb))
    G.append((clock()-te,
              'eyquem 2, use of zip and iterator iter'
              '\nlist(zip(ita,itb))'))


    from itertools import islice
    te = clock()
    for rep in range(n):
        if len(b)>len(a):
            ey3 = list(zip(iter(a) , islice(b,len(b)-len(a),None)))
        else:
            ey3 = list(zip(islice(a,len(a)-len(b),None),iter(b)))
    H.append((clock()-te,
              'eyquem 3, use of zip and iterators iter AND islice'
              '\nlist(zip(iter(a),islice(b,len(b)-len(a),None)))'))


    te = clock()
    for rep in range(n):
        ray = list(reversed(list(zip(reversed(a),reversed(b)))))
    I.append((clock()-te,
              'Raymond Hettinger, use of zip and iterator reversed'
              '\nlist(reversed(list(zip(reversed(a),reversed(b)))))'))


print( 'len(a) == %d\nlen(b) == %d\n' % (len(a),len(b)) )

tempi = [min(x) for x in (A,B,C,D,E,F,G,H,I)]
tempi.sort(reverse=True)
tref = tempi[0][0]/100
print( '\n\n'.join('%.2f %%     %s' % (t/tref,ch) for t,ch in tempi) )


print('\nsam1==sam2==fj==sleep==ey1==ey1bis==ey2==ey3==ray  is ',sam1==sam2==fj==sleep==ey1==ey1bis==ey2==ey3==ray)

結果列表的長度非常不同:

len(a) == 20000
len(b) == 50000

100.00 %     Sam Hocevar, exactly normal slicing and zip
k = min(len(a),len(b))
list(zip(a[len(a)-k:], b[len(b)-k:]))

99.80 %     Sam Hocevar, deducted normal slicing and zip
k = min(len(a),len(b))
list(zip(a[-k:], b[-k:]))

98.02 %     sleeplessnerd, exactly normal slicing and zip
m = min(len(a),len(b))
list(zip(a[len(a)-m:],b[len(b)-m:]))

97.98 %     F.J. , deducted tricky slicing and zip
list(zip(a[-len(b):], b[-len(a):]))

82.30 %     eyquem 2, use of zip and iterator iter
list(zip(ita,itb))

69.61 %     eyquem 1, deducted normal slicing and listcomp
m = min(len(a),len(b))
[ (a[-m+i],b[-m+i]) for i in range(m) ]

67.62 %     eyquem 1 improved, exactly normal slicing and listcomp
m = min(len(a),len(b)
x,y = len(a)-m , len(b)-m
[(a[x+i],b[y+i]) for i in range(m)]

61.23 %     eyquem 3, use of zip and iterators iter AND islice
list(zip(iter(a),islice(b,len(b)-len(a),None)))

60.92 %     Raymond Hettinger, use of zip and iterator reversed
list(reversed(list(zip(reversed(a),reversed(b)))))

sam1==sam2==fj==sleep==ey1==ey1bis==ey2==ey3==ray  is  True

結果有兩個相似長度的列表:

len(a) == 49500
len(b) == 50000

100.00 %     Sam Hocevar, deducted normal slicing and zip
k = min(len(a),len(b))
list(zip(a[-k:], b[-k:]))

99.39 %     F.J. , deducted tricky slicing and zip
list(zip(a[-len(b):], b[-len(a):]))

99.12 %     sleeplessnerd, exactly normal slicing and zip
m = min(len(a),len(b))
list(zip(a[len(a)-m:],b[len(b)-m:]))

98.10 %     Sam Hocevar, exactly normal slicing and zip
k = min(len(a),len(b))
list(zip(a[len(a)-k:], b[len(b)-k:]))

69.91 %     eyquem 1, deducted normal slicing and listcomp
m = min(len(a),len(b))
[ (a[-m+i],b[-m+i]) for i in range(m) ]

66.54 %     eyquem 1 improved, exactly normal slicing and listcomp
m = min(len(a),len(b)
x,y = len(a)-m , len(b)-m
[(a[x+i],b[y+i]) for i in range(m)]

58.94 %     Raymond Hettinger, use of zip and iterator reversed
list(reversed(list(zip(reversed(a),reversed(b)))))

51.29 %     eyquem 2, use of zip and iterator iter
list(zip(ita,itb))

51.17 %     eyquem 3, use of zip and iterators iter AND islice
list(zip(iter(a),islice(b,len(b)-len(a),None)))

sam1==sam2==fj==sleep==ey1==ey1bis==ey2==ey3==ray  is  True

我的結論是有三組解決方案:

  • Sam Hocevar,FJ和sleeplessnerd的解決方案執行時間最長。
    他們使用切片和函數zip()的不同組合。
    順便說一下,絕大多數人認可Sam的解決方案是最長的。

  • 我的函數rzip()和rzip() - 在上述組的68%的時間內改進了執行。
    他們只使用列表理解其索引獲得的元素

  • 我的解決方案是eyquem2和eyquem3,以及Raymond Hettinger的解決方案,不到前述時間的61%。
    他們使用迭代器。

我的解決方案的執行時間取決於列表的相對長度:
對於相似長度的列表,解決方案eyquem2和eyquem3的執行次數除以2!
但對於非常不同的列表,eyquem2令人驚訝地占用了參考時間的82%。

持續執行的時間約為Raymond Hettinger解決方案參考時間的60%,證實了他的主張。
我的解決方案eyquem3 with iter()islice()也不是那么糟糕,但它並不像Raymond Hettinger那樣清晰,盡管后者乍一看也有點模糊。

zip(a[len(a)-min(len(a), len(b)):], b[len(b)-min(len(a), len(b)):])

但它看起來不是很“pythonic”:P

[更新以增加反向排序的可能性(因為我以為我可能會使用這一天)]

作為發電機,你可以嘗試,

def reversed_zip(*l, from_right=False):

    i = min(len(l) for l in l)
    i, j, k = (1, i+1, 1) if from_right else (i, 0, -1) 

    while i != j:
        yield tuple( x[-i] for x in l ) 
        i += k

這不需要復制列表,並給出,

>>> a = [1,2,3]
>>> b = [4,5,6,7]

>>> list(reversed_zip(a, b))
[(1, 5), (2, 6), (3, 7)]

>>> list(reversed_zip(a, b, from_right=True))
[(3, 7), (2, 6), (1, 5)]

暫無
暫無

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

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