파이썬에서 목록을 회전시키는 효율적인 방법


263

파이썬에서 목록을 회전시키는 가장 효율적인 방법은 무엇입니까? 지금 나는 이와 같은 것을 가지고있다 :

>>> 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]

더 좋은 방법이 있습니까?


12
다른 언어 (Perl, Ruby)가이 용어를 사용하기 때문에 이것은 실제로 바뀌지 않습니다. 회전입니다. 어쩌면 질문은 그에 따라 업데이트되어야합니까?
Vincent Fourmond 2019 년

정말 원래 솔루션과 같은 @dzhelil 것은 돌연변이를 도입하지 않기 때문에
juanchito


2
나는 rotate옳지 않은 단어 라고 생각 합니다 shift.
codeforester

2
실제 정답은, 당신이 결코 처음부터 목록을 회전되어서는 안됩니다. "머리"또는 "꼬리"가 되고자하는 목록의 논리적 위치에 "포인터"변수를 작성하고 목록의 항목을 이동하는 대신 해당 변수를 변경하십시오. "모듈러스"연산자 %를 찾아서 목록의 시작과 끝 주위에 포인터를 "포장"하는 효율적인 방법을 찾으십시오.
cnd

답변:


280

A collections.deque는 양쪽 끝을 당기고 밀도록 최적화되어 있습니다. 그들은 심지어 전용 rotate()방법이 있습니다.

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
미래의 리더를 들어 : collections.deque rotate()에 따라 빠른 슬라이스보다 wiki.python.org/moin/TimeComplexity
제프

2
그러나 사용 deque.rotate하려면 deque먼저 객체로 의 유형 변환이 필요합니다 l.append(l.pop(0)). 따라서 deque 객체로 시작하는 것이 가장 빠릅니다. 그렇지 않으면을 사용하십시오 l.append(l.pop(0)).
Purrell

8
자세히 설명하면 deque.rotateO (k)이지만 list에서 deque 로의 유형 변환은 O (n) 입니다. 따라서 목록으로 시작하면 deque.rotate를 사용하는 것은 O (n) + O (k) = O (n)입니다. l.append(l.pop(0))반면에 O (1)입니다.
Purrell

3
@Purrell, 프론트 아이템 터지는 것은 O (n)입니다. wiki.python.org/moin/TimeComplexity에서는 O (k)로 표시되며 k는 팝된 항목 다음에 오는 목록의 요소 수입니다. 데이터 구조는 모든 다음 요소를 목록 앞쪽으로 이동하기 때문입니다. 이러한 이유로 O (1) 시간에 마지막 요소 만 팝업 할 수 있습니다.
Kirk Boyer

88

그냥 사용하는 것은 pop(0)어떻습니까?

list.pop([i])

목록에서 지정된 위치에있는 항목을 제거하고 반환하십시오. 인덱스를 지정하지 않으면 a.pop()목록의 마지막 항목을 제거하고 반환합니다. ( i메소드 서명에서 괄호 안의 대괄호 는 매개 변수가 선택적이며 해당 위치에 대괄호를 입력하지 않아야 함을 나타냅니다.이 표기법은 Python Library Reference에서 자주 볼 수 있습니다.)


16
그러나 k가 남아있는 요소의 수인 목록에서 각 요소를 제거하는 데 O (k)가 들지 않습니다. 총 시간은 O (n ^ 2)입니다. wiki.python.org/moin/TimeComplexity
Pramod

5
이것은 실제로 질문에 대답하지 않습니다. 문제는 항목을 순서대로 반환하는 것이 아니라 다른 순서로 새 목록을 만드는 것입니다.
user650261

5
아니요, pop을 사용한 질문에 대한 대답은입니다 l.append(l.pop(0). 내가 실수하지 않으면 O (1)입니다.
Purrell

4
list.pop은 내부적으로 memmove를 사용하여 모든 항목을 매우 빠르게 이동시키는 list_ass_slice를 호출하지만 여전히 O (n)입니다. github.com/python/cpython/blob/master/Objects/listobject.cwiki.python.org/moin/TimeComplexity를 참조하십시오 . 일정한 시간에 파이썬 목록에서 제거 할 수있는 유일한 항목은 마지막입니다.
DRayX

2
공감. 에서 docs.python.org/3/tutorial/... 이 첨가 된 첫번째 요소가 검색의 첫 번째 요소 인 대기열로 목록을 사용하는 것도 가능하다 ( "선입 선출"); 그러나 목록은이 목적에 비효율적입니다. 목록의 끝에서 추가 및 팝은 빠르지 만 목록의 시작 부분에서 삽입 또는 팝을 수행하는 것은 느립니다 (다른 모든 요소는 하나씩 이동해야하기 때문에).
SantaXL

59

Numpy는 다음 roll명령을 사용하여이를 수행 할 수 있습니다 .

>>> 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에 대한 사랑은 답변을 공급 가끔 다운이 하나 : 같은 훌륭한 새로운 보물을 찾을 수 있다는 것입니다
noamgot

내가 테스트했을 때 이것은 매우 느리다
Peter Harrison

@PeterHarrison : 테스트 세부 정보를 제공하지 않으므로 의미가 무엇인지 알기가 어렵습니다. 이 답변 은 전체 테스트 세부 사항과 타이밍 비교를 제공합니다.
리처드

33

이 작업을 수행 할 때 수행하려는 작업에 따라 다릅니다.

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

다음을 변경하고 싶을 수도 있습니다.

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

에:

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

5
주의 : 이것은 빈 목록에 대해 충돌합니다.
meawoppl

n = n % len (seq) return = seq [-n :] + seq [:-n]
user3303020

왜 n = n % len (seq)인지 설명 할 수 있습니까?
AerysS

16

내가 생각할 수있는 가장 간단한 방법 :

a.append(a.pop(0))

3
이것이리스트를위한 가장 빠른 방법입니다. collections.deque속도는 빠르지 만 단일 반복 또는 여러 반복의 경우 목록 길이가 가장 일반적인 경우에는 a.append(a.pop(0))deque로 변환하는 형식보다 빠릅니다.
Purrell

@runDOS 이 질문에 대한 완벽한 답변 은 슬프게도 중복으로 마감됩니다. 어쩌면 당신은 그것을 다시 열 투표?
Wolf

15

별도의 데이터 구조를 구성하는 대신 이러한 요소 집합을 반복하려면 반복자를 사용하여 생성기 표현식을 구성하십시오.

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

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

11

또한 목록을 제자리로 이동 (변경)하거나 함수가 새 목록을 반환하도록할지 여부에 따라 다릅니다. 내 테스트에 따르면 다음과 같은 것이 두 가지 목록을 추가하는 구현보다 20 배 이상 빠르기 때문입니다.

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

실제로, l = l[:]전달 된 목록의 사본을 조작하기 위해 맨 위에 a 를 추가해도 여전히 두 배 빠릅니다.

http://gist.github.com/288272 에서 일부 타이밍을 사용한 다양한 구현


3
대신에 l[:n] = []갈 것입니다 del l[:n]. 그냥 대안입니다.
tzot

1
예, 델. 나는 종종 델을 잊어 버린다. 메서드가 아닌 명령문 인 목록 작업 py3k가 그 변덕을 바 꾸었습니까, 아니면 여전히 얻었습니까?
keturn

2
@keturn : del은 여전히 Py3 의 진술입니다. 그러나 x.__delitem__(y) <==> del x[y], 만약 당신이 방법을 사용하는 것을 선호한다면, l.__delitem__(slice(n))또한 동등하며 2와 3 모두에서 작동합니다.
martineau

9

타이밍에 대한 몇 가지 참고 사항 :

목록으로 시작하는 l.append(l.pop(0))경우 가장 빠른 방법입니다. 시간 복잡성만으로도이를 보여줄 수 있습니다.

  • deque.rotate는 O (k)입니다 (k = 요소 수).
  • 변환을 해제하는 목록은 O (n)입니다.
  • list.append와 list.pop은 모두 O (1)입니다.

따라서 deque객체 로 시작하는 경우 deque.rotate()O (k)를 희생 할 수 있습니다 . 그러나 시작점이 목록이면 사용의 시간 복잡도 deque.rotate()는 O (n)입니다. l.append(l.pop(0)O (1)에서 더 빠릅니다.

설명을 위해 1M 반복에 대한 샘플 타이밍이 있습니다.

타입 변환이 필요한 메소드 :

  • deque.rotatedeque 객체로 : 0.12380790710449219 초 (가장 빠름)
  • deque.rotate유형 변환 사용시 : 6.853878974914551 초
  • np.rollnparray 사용시 : 6.0491721630096436 초
  • np.roll유형 변환 사용시 : 27.558452129364014 초

여기에 언급 된 방법을 나열하십시오.

  • l.append(l.pop(0)): 0.32483696937561035 초 (가장 빠름)
  • " shiftInPlace": 4.819645881652832 초
  • ...

사용 된 타이밍 코드는 다음과 같습니다.


collections.deque

목록에서 deques를 만드는 것은 O (n)임을 보여줍니다.

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 객체를 만들어야하는 경우 :

1M 반복 @ 6.853878974914551 초

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)

이미 deque 객체가있는 경우 :

0.12380790710449219 초에서 1M 반복

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

nparray를 만들어야하는 경우

1M 반복 @ 27.558452129364014 초

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
"""

이미 nparray가있는 경우 :

6.0491721630096436 초에서 1M 반복

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)

"자리에 이동"

타입 변환이 필요하지 않습니다

4.819645881652832 초에서 1M 반복

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. 첨부 (l.pop (0))

타입 변환이 필요하지 않습니다

1M 반복 @ 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 ()은 상수 시간 작업이지만 list.pop (0)은 아닙니다 . 목록 길이와 관련하여 선형 시간으로 실행됩니다. timeit 설정을 수정하여 테스트 할 수 있습니다 :l = [random.random() for i in range(100000)]
emu

1
list.pop은 일정한 시간 작업이 아닙니다. list.pop은 O (k) 시간에 실행되며, 여기서 k는 제거 된 요소를 지난 요소 수이므로 list.pop (0)은 O (n)입니다. 내부적으로 list.pop은 memmove를 사용하여 파이썬보다 더 빠르게 항목을 이동하는 list_ass_slice를 사용하지만 긴 목록의 경우 여전히 시간이 많이 걸립니다. 참조 github.com/python/cpython/blob/master/Objects/listobject.cwiki.python.org/moin/TimeComplexity
DRayX

타이밍 주셔서 감사합니다 (댓글 @emu). 우리는 이것이 l.append(l.pop(0))짧은리스트 (약 7 개의 요소)를 하나씩 바꾸는데 가장 좋은 성능 이라고 말할 수 있습니까?
Wolf

다시 한 번, l.append(l.pop(0))답변으로 : 이 질문 은 중복으로 종료됩니다. 어쩌면 당신은 그것을 다시 열 투표?
Wolf

8

나는 이것에 관심이 있었고 제안 된 솔루션 중 일부를 perfplot (작은 프로젝트) 과 비교했습니다 .

그것은 밝혀졌다

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

이다 훨씬 작은 변화를위한 가장 빠른 방법 n.

큰 들어 n,

data[n:] + data[:n]

나쁘지 않습니다.

본질적으로 perfplot은 큰 배열을 늘리기 위해 이동을 수행하고 시간을 측정합니다. 결과는 다음과 같습니다.

shift = 1:

여기에 이미지 설명을 입력하십시오

shift = 100:

여기에 이미지 설명을 입력하십시오


줄거리를 재현하는 코드 :

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)",
)

당신이 만든 멋진 도구. 에 관한 l.append(l.pop(0))답변으로 : 이 질문은 중복으로 닫힙니다. 어쩌면 당신은 그것을 다시 열 투표?
Wolf

4

아마도 링 버퍼가 더 적합 할 것입니다. 목록은 아니지만 목적에 따라 목록처럼 충분히 작동 할 수 있습니다.

문제는리스트의 시프트 효율이 O (n)이며, 이는 충분히 큰리스트에 대해 중요해진다는 것입니다.

링 버퍼의 이동은 단순히 O (1) 인 헤드 위치를 업데이트하는 것입니다.


4

변경 불가능한 구현의 경우 다음과 같이 사용할 수 있습니다.

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

효율성이 목표라면 (주기? 메모리?) 배열 모듈을 보는 것이 좋습니다. http://docs.python.org/library/array.html

배열에는 목록의 오버 헤드가 없습니다.

그러나 순수한 목록에 관한 한, 당신이 원하는 것은 당신이 할 수있는만큼 좋은 것입니다.


3

나는 당신이 이것을 찾고 있다고 생각합니다 :

a.insert(0, x)

질문과 답변 사이의 관계가 보이지 않습니다. 설명해 주시겠습니까?
Wolf

2

다른 대안 :

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

1

이 비용 모델을 참조로 사용합니다.

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

목록을 분할하고 두 개의 하위 목록을 연결하는 방법은 선형 시간 작업입니다. 상수 시간 작업 인 pop을 사용하는 것이 좋습니다.

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

2
업데이트 : wiki.python.org/moin/TimeComplexity 보다 나은 참조로 사용하십시오 .popcollections.dequeue 과 appendleft를 사용 하십시오.이 둘은 O (1) op입니다. 위의 첫 번째 대답에서 insert는 O (n)입니다.
herrfz

1
이어야한다collections.deque
herrfz

1

이것이 '효율적인지'모르지만 작동합니다.

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

편집 : 안녕하세요, 방금이 솔루션에 큰 문제가 있음을 발견했습니다! 다음 코드를 고려하십시오.

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 () 메서드는 내 x.insert (0, x.pop ()) 솔루션과 동일한 코드를 실행하고 otherlist는 클래스와 독립적 인 목록입니다. otherlist의 내용을 MyClass.classlist 목록으로 전달한 후 shift_classlist ()를 호출하면 otherlist 목록도 변경됩니다.

콘솔 출력 :

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!

파이썬 2.7을 사용합니다. 그게 버그인지는 모르겠지만 여기서 뭔가를 잘못 이해했을 가능성이 높습니다.

왜 이런 일이 일어나는지 아십니까?


2
때문이 발생 x.classlist = otherlist차종이 x.classlist같은 목록을 참조 otherlist하고 전화 할 때 x.shift_classlist()변이에게 목록을 모두 이름이 동일한 목록 객체를 참조하기 때문이다. 두 개체 이름은 동일한 개체에 대한 별칭 일 뿐이므로 변경되는 것처럼 보입니다. x.classlist = otherlist[:]대신 목록의 사본을 할당하는 데 사용하십시오 .
Dan D.

와우! 대단히 감사합니다! 나는 그것을 정말로 몰랐다. 그리고 그것은 정말로 알고있다! :)
wese3112

1

다음 방법은 보조 메모리가 일정한 O (n)입니다.

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

파이썬 에서이 접근법은 다른 조각에 비해 끔찍하게 비효율적입니다. 어떤 조각의 기본 구현을 활용할 수 없기 때문입니다.


실제로 list.pop과 list.append를 사용할 수 있습니다. 상수 시간 인 "l.append (l.pop (0))"을 작성할 수있을 때 O (n) 인 12 행 함수를 작성하는 것은 언어의 잘못이 아닙니다.
Purrell

l.append (l.pop (0))은 O (n) (l.pop (0)은 모든 요소를 ​​이동해야 함)이므로 m 값을 이동하려면 복잡도는 실제로 O (n * m)입니다. 내가 제공 한 알고리즘의 복잡성은 시프트 수에 관계없이 O (n)입니다. 너무 많은 로직 (list.pop이 C로 구현되어, 참조 대신 C의 파이썬 작전에서 수행되기 때문에 실제로,이 느린 github.com/python/cpython/blob/master/Objects/listobject.c을 ).
DRayX

1

나는 비슷한 것을 가지고 있습니다. 예를 들어, 2만큼 이동하려면 ...

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

1

가장 효율적인 방법이 있다고 생각합니다

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

0

사용 사례는 무엇입니까? 실제로 완전히 시프트 된 어레이가 필요하지 않은 경우가 있습니다. 시프트 된 어레이의 소수의 요소에만 액세스하면됩니다.

파이썬 슬라이스를 얻는 것은 런타임 O (k)입니다. 여기서 k는 슬라이스이므로 슬라이스 회전은 런타임 N입니다. deque rotation 명령도 O (k)입니다. 더 잘할 수 있을까요?

매우 큰 배열을 생각해보십시오 (예를 들어, 계산하기가 느리면 슬라이스 속도가 느립니다). 대안 솔루션은 원래 배열을 그대로두고 어떤 종류의 이동 후 원하는 인덱스에 존재했을 항목의 인덱스를 간단히 계산하는 것입니다.

시프트 된 요소에 액세스하면 O (1)이됩니다.

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

다음 함수는 전송 된 목록을 임시 목록에 복사하므로 pop 함수는 원래 목록에 영향을 미치지 않습니다.

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

테스트 :

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)

산출:

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

Programming Pearls (Column 2)의 Jon Bentley 는 n요소 벡터 xi위치 별로 왼쪽으로 회전시키는 우아하고 효율적인 알고리즘을 설명합니다 .

배열 ab을 배열 로 변환하는 것으로 문제를 ba보자. 그러나 배열 의 지정된 부분에서 요소를 뒤집는 함수가 있다고 가정하자. 시작 ab, 우리는 반대로 a얻기 위해 역 얻기 위해 얻을 수있는 모든 일을 반대로 다음과 정확히 일치하는 . 결과적으로 다음과 같은 회전 코드가 생성됩니다.arbbarbr(arbr)rba

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

이것은 다음과 같이 파이썬으로 번역 될 수 있습니다 :

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

데모:

>>> 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

리스트 X = ['a', 'b', 'c', 'd', 'e', 'f']shift 리스트 길이보다 작은 원하는 시프트 값에 대해 , 우리는 다음과 같이 함수 list_shift()를 정의 할 수 있습니다

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

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


1
바로 OP가 가진 것입니다. 방금 이름을 변경하고 어설 션을 추가했습니다.
RufusVS

기능 list_shift당신의 대답은 함수와 동일 shift이 실제 질문에 대한 답변되지 않도록, 원래의 질문에 "더 좋은 방법이 있나요?"
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))

예를 들어, 주어진

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

함수는를 반환해야합니다 [9, 7, 6, 3, 8]. 세 번의 회전이 이루어졌습니다.

[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]

다른 예를 들어, 주어진

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

이 함수는 [0, 0, 0]

주어진

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

이 함수는 [1, 2, 3, 4]


0

이 문제에 대한 해결책을 찾고있었습니다. 이것은 O (k)의 목적을 해결합니다.

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

다른 언어로의 전환과 비슷한 기능 :

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

1
-1 : 이것은 요청 된 것과 다른 일을하고 있으며 BTW는L.pop(0)
6502
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.