Python'da bir listeyi döndürmenin etkili yolu


263

Python'da bir listeyi döndürmenin en etkili yolu nedir? Şu anda böyle bir şey var:

>>> def rotate(l, n):
...     return l[n:] + l[:n]
... 
>>> l = [1,2,3,4]
>>> rotate(l,1)
[2, 3, 4, 1]
>>> rotate(l,2)
[3, 4, 1, 2]
>>> rotate(l,0)
[1, 2, 3, 4]
>>> rotate(l,-1)
[4, 1, 2, 3]

Daha iyi bir yol var mı?


12
Diğer diller (Perl, Ruby) terimini kullandığından bu gerçekten değişmez. Bu döndür. Belki soru buna göre güncellenmelidir?
Vincent Fourmond

@dzhelil Mutasyon getirmediği için orijinal çözümünüzü gerçekten çok seviyorum
juanchito


2
Bence rotatedoğru kelime değil shift.
codeforester

2
Gerçek doğru cevap, asla ilk etapta liste dönen edilmelidir. Listenizdeki "head" (kafa) veya "tail" (kuyruk) olmasını istediğiniz mantıksal yere bir "pointer" değişkeni oluşturun ve listedeki öğelerden herhangi birini taşımak yerine bu değişkeni değiştirin. İşaretçinizi listenin başlangıcında ve bitişinde "kaydırmak" için etkili bir yol için "modulo" operatörüne% bakın.
cnd

Yanıtlar:


280

A collections.deque, her iki ucu da çekmek ve itmek için optimize edilmiştir. Hatta özel bir rotate()yöntemleri var.

from collections import deque
items = deque([1, 2])
items.append(3)        # deque == [1, 2, 3]
items.rotate(1)        # The deque is now: [3, 1, 2]
items.rotate(-1)       # Returns deque to original state: [1, 2, 3]
item = items.popleft() # deque == [2, 3]

8
Gelecekteki okuyucular için: wiki.python.org/moin/TimeComplexity'yecollections.deque rotate() göre dilimlemekten daha hızlı
Geoff

2
Ancak dikkat edin, kullanmak önce deque.rotatebir dequenesneye bir tür dönüştürme gerektirir , bu da daha yavaştır l.append(l.pop(0)). Yani başlamak için bir deque nesneniz varsa, en hızlı olduğundan emin olun. Aksi takdirde kullanın l.append(l.pop(0)).
Purrell

8
Ayrıntılı olarak, deque.rotateO (k) 'dir, ancak listeden deque'ye dönüşüm yazın O (n) . Bir listeyle başlarsanız, deque.rotate komutunu kullanmak O (n) + O (k) = O (n) olur. l.append(l.pop(0))diğer yandan O (1) 'dir.
Purrell

3
@Purrell, ön öğeyi patlatmak O (n). Wiki.python.org/moin/TimeComplexity öğesinde O (k) olarak listelenir ve k, açılan öğeyi izleyen listedeki öğelerin sayısıdır, çünkü veri yapısı aşağıdaki tüm öğeleri listenin önüne kaydırır. Bu nedenle O (1) zamanında sadece son eleman patlayabilir.
Kirk Boyer

88

Sadece kullanmaya ne dersiniz pop(0)?

list.pop([i])

Öğeyi listede belirtilen konumda kaldırın ve iade edin. Herhangi bir dizin belirtilmezse, a.pop()listedeki son öğeyi kaldırır ve döndürür. ( iYöntem imzasının etrafındaki köşeli parantezler , parametrenin isteğe bağlı olduğunu belirtir, bu konuma köşeli parantezler yazmanız gerektiğini değil. Bu gösterimi Python Library Reference içinde sık sık göreceksiniz.)


16
Ancak listedeki her bir öğenin kaldırılması, k'nin kalan öğe sayısı olduğu için O (k) 'ya mal olmaz. Böylece toplam süre O (n ^ 2) olacaktır wiki.python.org/moin/TimeComplexity
Pramod

5
Bu soruya gerçekten cevap vermiyor. Soru, öğeleri sırayla iade etmek değil, farklı bir sırada olan yeni bir liste oluşturmakla ilgilidir.
user650261

5
hayır, pop kullanarak sorunun cevabı olacaktır l.append(l.pop(0). Yanılmıyorsam O (1).
Purrell

4
list.pop dahili olarak tüm öğeleri çok hızlı bir şekilde taşımak için memmove kullanan list_ass_slice'yi çağırır, ancak yine de O (n). Bkz. Github.com/python/cpython/blob/master/Objects/listobject.c ve wiki.python.org/moin/TimeComplexity . Sabit bir zamanda bir python listesinden çıkarılabilen tek öğe sonuncusudur.
DRayX

2
Downvoted. Kaynaktan docs.python.org/3/tutorial/... ilave birinci eleman alınan birinci eleman olan bir sıra, bir listesini kullanmak da mümkündür ( “ilk giren ilk çıkar”); ancak, listeler bu amaçla etkili değildir. Listenin sonundaki ekleme ve çıkmalar hızlı olmakla birlikte, listenin başından itibaren ekleme veya çıkarma yapmak yavaştır (çünkü diğer tüm öğelerin birer birer kaydırılması gerekir).
SantaXL

59

Numpy şu rollkomutu kullanarak bunu yapabilir :

>>> import numpy
>>> a=numpy.arange(1,10) #Generate some data
>>> numpy.roll(a,1)
array([9, 1, 2, 3, 4, 5, 6, 7, 8])
>>> numpy.roll(a,-1)
array([2, 3, 4, 5, 6, 7, 8, 9, 1])
>>> numpy.roll(a,5)
array([5, 6, 7, 8, 9, 1, 2, 3, 4])
>>> numpy.roll(a,9)
array([1, 2, 3, 4, 5, 6, 7, 8, 9])

1
SO hakkında sevdiğim şey, bazen cevaplar beslemesinde bunun gibi bazı yeni hazineler bulabilmenizdir :)
noamgot

Bu, test ettiğimde, çok, çok yavaş
Peter Harrison

@PeterHarrison: Test ayrıntılarını sağlamadığınız için ne demek istediğinizi bilmek bile zor. Bu yanıt , tam test ayrıntıları ve zamanlama karşılaştırması sağlar.
Richard

33

Bunu yaptığınızda ne olmasını istediğinize bağlıdır:

>>> shift([1,2,3], 14)

Aşağıdakileri değiştirmek isteyebilirsiniz:

def shift(seq, n):
    return seq[n:]+seq[:n]

için:

def shift(seq, n):
    n = n % len(seq)
    return seq[n:] + seq[:n]

5
Not: Bu boş listeler için kilitlenir.
meawoppl

n = n% len (seq) dönüş = seq [-n:] + seq [: - n]
user3303020

Neden n = n% len (seq) açıklayabilir misiniz?
AerysS

16

Düşünebileceğim en basit yol:

a.append(a.pop(0))

3
Bu listeler için en hızlı yoldur. collections.dequedaha hızlıdır, ancak tek bir yinelemede veya birden çok yinelemede en yaygın liste uzunluğu vakaları için, a.append(a.pop(0))
deque'ye

@runDOSrun, yinelenen bir şekilde kapalı olan bu soruya mükemmel bir cevap . Belki yeniden açmak için oy kullanırsınız?
Wolf

15

Yalnızca ayrı bir veri yapısı oluşturmak yerine bu öğe kümelerini yinelemek istiyorsanız, bir jeneratör ifadesi oluşturmak için yineleyicileri kullanmayı düşünün:

def shift(l,n):
    return itertools.islice(itertools.cycle(l),n,n+len(l))

>>> list(shift([1,2,3],1))
[2, 3, 1]

11

Bu, listeyi yerinde değiştirmek (değiştirerek) veya işlevin yeni bir liste döndürmesini isteyip istemediğinize de bağlıdır. Çünkü, testlerime göre, böyle bir şey iki liste ekleyen uygulamanızdan en az yirmi kat daha hızlıdır:

def shiftInPlace(l, n):
    n = n % len(l)
    head = l[:n]
    l[:n] = []
    l.extend(head)
    return l

Aslında, l = l[:]aktarılan listenin bir kopyası üzerinde çalışmak için bunun üstüne a eklemek bile iki kat daha hızlıdır.

Http://gist.github.com/288272 adresinde zamanlama ile çeşitli uygulamalar


3
Onun yerine l[:n] = []giderdim del l[:n]. Sadece bir alternatif.
tzot

1
Oh, evet, eski güzel del. Sık sık del unutuyorum; liste işlemi bir yöntem değil, bir deyimdir. Py3k bu tuhaflığı değiştirdi mi, yoksa hala anladık mı?
Ocak'ta keturn

2
@keturn: Py3'te delhala bir ifade. Ancak x.__delitem__(y) <==> del x[y], yöntemleri kullanmayı tercih ederseniz, l.__delitem__(slice(n))aynı zamanda eşdeğerdir ve hem 2 hem de 3'te çalışır
martineau

9

Zamanlamayla ilgili bazı notlar:

Bir listeyle başlıyorsanız l.append(l.pop(0)), kullanabileceğiniz en hızlı yöntem budur. Bu sadece zaman karmaşıklığı ile gösterilebilir:

  • deque.rotate O (k) (k = eleman sayısı)
  • deque dönüşüm listesi O (n)
  • list.append ve list.pop ikisi de O (1)

Yani dequenesnelerle başlıyorsanız deque.rotate(), O (k) pahasına yapabilirsiniz . Ancak, başlangıç ​​noktası bir liste ise, kullanımın zaman karmaşıklığı deque.rotate()O (n) 'dir. l.append(l.pop(0)O (1) 'de daha hızlıdır.

Sadece gösterim uğruna, 1M yinelemelerinde bazı örnek zamanlamalar:

Tür dönüşümü gerektiren yöntemler:

  • deque.rotatedeque nesnesi ile: 0.12380790710449219 saniye (en hızlı)
  • deque.rotatetip dönüşümü ile: 6.853878974914551 saniye
  • np.rollnparray ile: 6.0491721630096436 saniye
  • np.rolltip dönüşümü ile: 27.558452129364014 saniye

Burada bahsedilen yöntemleri listeleyin:

  • l.append(l.pop(0)): 0.32483696937561035 saniye (en hızlı)
  • " shiftInPlace": 4.819645881652832 saniye
  • ...

Kullanılan zamanlama kodu aşağıdadır.


collections.deque

Listelerden deque oluşturmanın O (n) olduğunu gösteren:

from collections import deque
import big_o

def create_deque_from_list(l):
     return deque(l)

best, others = big_o.big_o(create_deque_from_list, lambda n: big_o.datagen.integers(n, -100, 100))
print best

# --> Linear: time = -2.6E-05 + 1.8E-08*n

Deque nesneleri oluşturmanız gerekiyorsa:

1M iterasyonları @ 6.853878974914551 saniye

setup_deque_rotate_with_create_deque = """
from collections import deque
import random
l = [random.random() for i in range(1000)]
"""

test_deque_rotate_with_create_deque = """
dl = deque(l)
dl.rotate(-1)
"""
timeit.timeit(test_deque_rotate_with_create_deque, setup_deque_rotate_with_create_deque)

Zaten deque nesneleriniz varsa:

1M iterasyonları @ 0.12380790710449219 saniye

setup_deque_rotate_alone = """
from collections import deque
import random
l = [random.random() for i in range(1000)]
dl = deque(l)
"""

test_deque_rotate_alone= """
dl.rotate(-1)
"""
timeit.timeit(test_deque_rotate_alone, setup_deque_rotate_alone)

np.roll

Nparraylar oluşturmanız gerekiyorsa

1M iterasyonları @ 27.558452129364014 saniye

setup_np_roll_with_create_npa = """
import numpy as np
import random
l = [random.random() for i in range(1000)]
"""

test_np_roll_with_create_npa = """
np.roll(l,-1) # implicit conversion of l to np.nparray
"""

Zaten nparraylarınız varsa:

1 milyon iterasyon @ 6.0491721630096436 saniye

setup_np_roll_alone = """
import numpy as np
import random
l = [random.random() for i in range(1000)]
npa = np.array(l)
"""

test_roll_alone = """
np.roll(npa,-1)
"""
timeit.timeit(test_roll_alone, setup_np_roll_alone)

"Yerinde kaydırma"

Tür dönüşümü gerektirmez

1M iterasyonları @ 4.819645881652832 saniye

setup_shift_in_place="""
import random
l = [random.random() for i in range(1000)]
def shiftInPlace(l, n):
    n = n % len(l)
    head = l[:n]
    l[:n] = []
    l.extend(head)
    return l
"""

test_shift_in_place="""
shiftInPlace(l,-1)
"""

timeit.timeit(test_shift_in_place, setup_shift_in_place)

l.append (l.pop (0))

Tür dönüşümü gerektirmez

1M iterasyonları @ 0.32483696937561035

setup_append_pop="""
import random
l = [random.random() for i in range(1000)]
"""

test_append_pop="""
l.append(l.pop(0))
"""
timeit.timeit(test_append_pop, setup_append_pop)

2
list.pop () sabit zamanlı bir işlemken list.pop (0) değildir . Liste uzunluğuna göre doğrusal zamanda çalışır. Bunu timeit kurulumunuzu değiştirerek test edebilirsiniz:l = [random.random() for i in range(100000)]
emu

1
list.pop sabit bir zaman işlemi değildir. list.pop, O (k) zamanında çalışır; burada k, kaldırılan öğeyi geçen öğe sayısıdır; bu nedenle list.pop (0), O (n) olur. Dahili olarak list.pop, öğeleri python ile her zamankinden daha hızlı taşımak için memmove kullanan list_ass_slice kullanır, ancak uzun listeler için hala çok zaman alıcıdır. Bkz. Github.com/python/cpython/blob/master/Objects/listobject.c ve wiki.python.org/moin/TimeComplexity
DRayX

Zamanlama için teşekkürler (ve yorumlar @emu). Öyleyse l.append(l.pop(0))kısa listelerin (yaklaşık 7 öğe) bire bir kaydırılması için en iyi performansın olduğunu söyleyebilir miyiz ?
Kurt

Yine, l.append(l.pop(0))bir cevap olarak: Bu soru kopya olarak kapalıdır. Belki yeniden açmak için oy kullanırsınız?
Wolf

8

Ayrıca bununla ilgilenmeye başladım ve önerilen çözümlerden bazılarını perfplot (küçük bir proje) ile karşılaştırdım.

Şekline dönüştü

for _ in range(n):
    data.append(data.pop(0))

olduğu kadar küçük vardiya için en hızlı yöntemle n.

Daha büyük için n,

data[n:] + data[:n]

fena değil.

Esasen, perfplot büyük dizileri arttırmak için geçiş yapar ve zamanı ölçer. Sonuçlar burada:

shift = 1:

resim açıklamasını buraya girin

shift = 100:

resim açıklamasını buraya girin


Grafiği yeniden oluşturmak için kod:

import numpy
import perfplot
import collections


shift = 100


def list_append(data):
    return data[shift:] + data[:shift]


def shift_concatenate(data):
    return numpy.concatenate([data[shift:], data[:shift]])


def roll(data):
    return numpy.roll(data, -shift)


def collections_deque(data):
    items = collections.deque(data)
    items.rotate(-shift)
    return items


def pop_append(data):
    for _ in range(shift):
        data.append(data.pop(0))
    return data


perfplot.save(
    "shift100.png",
    setup=lambda n: numpy.random.rand(n).tolist(),
    kernels=[list_append, roll, shift_concatenate, collections_deque, pop_append],
    n_range=[2 ** k for k in range(7, 20)],
    logx=True,
    logy=True,
    xlabel="len(data)",
)

Yaptığınız güzel araç. İlgili l.append(l.pop(0))bir cevap olarak: Bu soru kopyası olarak kapatılır. Belki yeniden açmak için oy kullanırsınız?
Wolf

4

Muhtemelen bir ringbuffer daha uygundur. Bir liste değildir, ancak amaçlarınız için bir liste gibi davranması muhtemeldir.

Sorun, bir listede kaymanın etkinliğinin O (n) olmasıdır, bu da yeterince büyük listeler için önemli hale gelir.

Bir ringbuffer'da geçiş yapmak, sadece O (1) olan kafa konumunu güncelliyor.


4

Değişmez bir uygulama için şöyle bir şey kullanabilirsiniz:

def shift(seq, n):
    shifted_seq = []
    for i in range(len(seq)):
        shifted_seq.append(seq[(i-n) % len(seq)])
    return shifted_seq

print shift([1, 2, 3, 4], 1)


3

Bence bunu arıyorsun:

a.insert(0, x)

Soru ile cevabınız arasındaki ilişkiyi görmüyorum. Lütfen açıklayabilir misiniz?
Kurt

2

Başka bir alternatif:

def move(arr, n):
    return [arr[(idx-n) % len(arr)] for idx,_ in enumerate(arr)]

1

Bu maliyet modelini referans olarak alıyorum:

http://scripts.mit.edu/~6.006/fall07/wiki/index.php?title=Python_Cost_Model

Listeyi dilimleme ve iki alt listeyi birleştirme yönteminiz doğrusal zamanlı işlemlerdir. Örneğin, sabit zamanlı bir işlem olan pop'u kullanmanızı öneririm:

def shift(list, n):
    for i in range(n)
        temp = list.pop()
        list.insert(0, temp)

2
update: bunu daha iyi bir referans olarak alın: wiki.python.org/moin/TimeComplexity , collections.dequeueher ikisi de O (1) ops olan pop ve appendleft kullanın . Yukarıdaki ilk cevabımda insert O (n).
herrfz

1
olmalıcollections.deque
herrfz

1

Bunun 'verimli' olup olmadığını bilmiyorum, ama aynı zamanda işe yarıyor:

x = [1,2,3,4]
x.insert(0,x.pop())

EDIT: Tekrar merhaba, bu çözüm ile büyük bir sorun buldum! Aşağıdaki kodu göz önünde bulundurun:

class MyClass():
    def __init__(self):
        self.classlist = []

    def shift_classlist(self): # right-shift-operation
        self.classlist.insert(0, self.classlist.pop())

if __name__ == '__main__':
    otherlist = [1,2,3]
    x = MyClass()

    # this is where kind of a magic link is created...
    x.classlist = otherlist

    for ii in xrange(2): # just to do it 2 times
        print '\n\n\nbefore shift:'
        print '     x.classlist =', x.classlist
        print '     otherlist =', otherlist
        x.shift_classlist() 
        print 'after shift:'
        print '     x.classlist =', x.classlist
        print '     otherlist =', otherlist, '<-- SHOULD NOT HAVE BIN CHANGED!'

Shift_classlist () yöntemi, x.insert (0, x.pop ()) - solution ile aynı kodu çalıştırır, otherlist, sınıftan bağımsız bir listedir. Diğer listenin içeriğini MyClass.classlist listesine ilettikten sonra, shift_classlist () öğesini çağırmak da diğer liste listesini değiştirir:

KONSOL ÇIKIŞI:

before shift:
     x.classlist = [1, 2, 3]
     otherlist = [1, 2, 3]
after shift:
     x.classlist = [3, 1, 2]
     otherlist = [3, 1, 2] <-- SHOULD NOT HAVE BIN CHANGED!



before shift:
     x.classlist = [3, 1, 2]
     otherlist = [3, 1, 2]
after shift:
     x.classlist = [2, 3, 1]
     otherlist = [2, 3, 1] <-- SHOULD NOT HAVE BIN CHANGED!

Python 2.7 kullanıyorum. Bu bir hata olup olmadığını bilmiyorum, ama sanırım burada bir şeyi yanlış anlamam daha olası.

Biriniz bunun neden olduğunu biliyor mu?


2
Çünkü olur x.classlist = otherlistmarkaları x.classlistile aynı listeye bakın otherlistve sonra Aradığınızda x.shift_classlist()mutasyona uğrar listesini onu ve her iki isim aynı liste nesnesine başvurmak çünkü. Her iki ad da değişiyor gibi görünüyor çünkü bunlar sadece aynı nesnenin diğer adları. x.classlist = otherlist[:]Bunun yerine listenin bir kopyasını atamak için kullanın .
Dan D.

Hey vay canına! Çok teşekkür ederim! Bunu gerçekten bilmiyordum ve bilmek gerçekten çok iyi! :)
wese3112

1

Aşağıdaki yöntem sabit yardımcı belleğe sahip O (n) yöntemidir:

def rotate(arr, shift):
  pivot = shift % len(arr)
  dst = 0
  src = pivot
  while (dst != src):
    arr[dst], arr[src] = arr[src], arr[dst]
    dst += 1
    src += 1
    if src == len(arr):
      src = pivot
    elif dst == pivot:
      pivot = src

Python'da, bu yaklaşımın herhangi bir parçanın doğal uygulamalarından yararlanamayacağı için diğerlerine kıyasla çok verimsiz olduğuna dikkat edin.


aslında, list.pop ve list.append komutlarını kullanabilirsiniz. O zaman, "l.append (l.pop (0))" yazdığınızda, O (n) olan 12 satırlık bir fonksiyon yazmanız dilin hatası değildir.
Purrell

l. ek (l.pop (0)) O (n) (l.pop (0) her öğeyi kaydırmalıdır), bu nedenle m değerlerini kaydırmak istiyorsanız karmaşıklık aslında O (n * m) 'dir. Sağladığım algoritmanın karmaşıklığı, vardiya sayısına bakılmaksızın O (n) 'dir. Uygulamada, bu yavaştır çünkü C yerine python ops'da çok fazla mantık yapılır (list.pop c'de uygulanır, bkz. Github.com/python/cpython/blob/master/Objects/listobject.c ).
DRayX

1

Benzer bir şeyim var. Örneğin, ikiye geçmek için ...

def Shift(*args):
    return args[len(args)-2:]+args[:len(args)-2]

1

Bence en etkili yol sende

def shift(l,n):
    n = n % len(l)  
    return l[-U:] + l[:-U]

0

Kullanım durumu nedir? Genellikle, tam olarak kaydırılmış bir diziye ihtiyacımız yoktur - sadece kaydırılan dizideki birkaç öğeye erişmemiz gerekir.

Python dilimleri elde etmek, k'nin dilim olduğu çalışma zamanı O (k) 'dır, bu nedenle dilimli bir dönüş çalışma zamanı N'dir. Deque döndürme komutu da O (k)' dır. Daha iyisini yapabilir miyiz?

Son derece büyük bir dizi düşünün (diyelim ki, o kadar büyük ki, dilimlemek için hesaplama açısından yavaş olacaktır). Alternatif bir çözüm, orijinal diziyi yalnız bırakmak ve basitçe, bir tür değişiklikten sonra arzu edilen dizinimizde var olan öğenin dizinini hesaplamak olacaktır.

Kaymış bir elemana erişim böylece O (1) olur.

def get_shifted_element(original_list, shift_to_left, index_in_shifted):
    # back calculate the original index by reversing the left shift
    idx_original = (index_in_shifted + shift_to_left) % len(original_list)
    return original_list[idx_original]

my_list = [1, 2, 3, 4, 5]

print get_shifted_element(my_list, 1, 2) ----> outputs 4

print get_shifted_element(my_list, -2, 3) -----> outputs 2 

0

Aşağıdaki işlev gönderilen listeyi bir geçici listeye kopyalar, böylece pop işlevi orijinal listeyi etkilemez:

def shift(lst, n, toreverse=False):
    templist = []
    for i in lst: templist.append(i)
    if toreverse:
        for i in range(n):  templist = [templist.pop()]+templist
    else:
        for i in range(n):  templist = templist+[templist.pop(0)]
    return templist

Test yapmak:

lst = [1,2,3,4,5]
print("lst=", lst)
print("shift by 1:", shift(lst,1))
print("lst=", lst)
print("shift by 7:", shift(lst,7))
print("lst=", lst)
print("shift by 1 reverse:", shift(lst,1, True))
print("lst=", lst)
print("shift by 7 reverse:", shift(lst,7, True))
print("lst=", lst)

Çıktı:

lst= [1, 2, 3, 4, 5]
shift by 1: [2, 3, 4, 5, 1]
lst= [1, 2, 3, 4, 5]
shift by 7: [3, 4, 5, 1, 2]
lst= [1, 2, 3, 4, 5]
shift by 1 reverse: [5, 1, 2, 3, 4]
lst= [1, 2, 3, 4, 5]
shift by 7 reverse: [4, 5, 1, 2, 3]
lst= [1, 2, 3, 4, 5]

0

Programlama İncileri'ndeki Jon Bentley (Sütun 2), bir neleman vektörünü konumlara xgöre döndürmek için zarif ve etkili bir algoritmayı açıklar i:

Sorunu diziyi diziye abdönüştürüyor olarak bagörelim, ancak dizinin belirli bir bölümündeki öğeleri tersine çeviren bir fonksiyonumuz olduğunu varsayalım. Başlangıç ​​olarak ab, aalmak için ters , almak için ters ve sonra almak için her şeyi tersine çeviririz , ki bu tam olarak . Bu, aşağıdaki dönüş koduyla sonuçlanır:arbbarbr(arbr)rba

reverse(0, i-1)
reverse(i, n-1)
reverse(0, n-1)

Bu, Python'a şu şekilde çevrilebilir:

def rotate(x, i):
    i %= len(x)
    x[:i] = reversed(x[:i])
    x[i:] = reversed(x[i:])
    x[:] = reversed(x)
    return x

Demo:

>>> def rotate(x, i):
...     i %= len(x)
...     x[:i] = reversed(x[:i])
...     x[i:] = reversed(x[i:])
...     x[:] = reversed(x)
...     return x
... 
>>> rotate(list('abcdefgh'), 1)
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'a']
>>> rotate(list('abcdefgh'), 3)
['d', 'e', 'f', 'g', 'h', 'a', 'b', 'c']
>>> rotate(list('abcdefgh'), 8)
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> rotate(list('abcdefgh'), 9)
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'a']

0

Bir liste X = ['a', 'b', 'c', 'd', 'e', 'f']ve shift liste uzunluğundan daha az istenen kaydırma değeri için işlevi list_shift()aşağıdaki gibi tanımlayabiliriz

def list_shift(my_list, shift):
    assert shift < len(my_list)
    return my_list[shift:] + my_list[:shift]

Örnekler,

list_shift(X,1)döner ['b', 'c', 'd', 'e', 'f', 'a'] list_shift(X,3)döner['d', 'e', 'f', 'a', 'b', 'c']


1
OP'nin sahip olduğu şey tam olarak bu. Az önce isimleri değiştirdiniz ve bir iddia eklediniz.
RufusVS

Fonksiyon list_shiftYanıtınızda işlevi aynıdır shiftbu fiili soruya bir cevap değil, orijinal söz konusu: "Daha iyi bir yolu var mı?"
RufusVS

0
def solution(A, K):
    if len(A) == 0:
        return A

    K = K % len(A)

    return A[-K:] + A[:-K]

# use case
A = [1, 2, 3, 4, 5, 6]
K = 3
print(solution(A, K))

Örneğin,

A = [3, 8, 9, 7, 6]
K = 3

işlev dönmelidir [9, 7, 6, 3, 8]. Üç rotasyon yapıldı:

[3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7]
[6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9]
[7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8]

Başka bir örnek için verilen

A = [0, 0, 0]
K = 1

işlev dönmelidir [0, 0, 0]

verilmiş

A = [1, 2, 3, 4]
K = 4

işlev dönmelidir [1, 2, 3, 4]


0

Bu soruna yerinde bir çözüm arıyordum. Bu O (k) 'daki amacı çözer.

def solution(self, list, k):
    r=len(list)-1
    i = 0
    while i<k:
        temp = list[0]
        list[0:r] = list[1:r+1]
        list[r] = temp
        i+=1
    return list

-3

Diğer dillerde shift ile benzer işlevler için:

def shift(l):
    x = l[0]
    del(l[0])
    return x

1
-1: Bu istenenden farklı bir şey yapıyor ve BTW daL.pop(0)
6502
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.