अजगर में एक सूची को घुमाने का कुशल तरीका


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
यह वास्तव में शिफ्ट नहीं है क्योंकि अन्य भाषाएं (पर्ल, रूबी) शब्द का उपयोग करती हैं। यह चक्कर है। हो सकता है कि प्रश्न तदनुसार अद्यतन किया जाना चाहिए?
विंसेंट फोरमंड

@dzhelil मुझे वास्तव में आपका मूल समाधान पसंद है क्योंकि यह उत्परिवर्तन का परिचय नहीं देता है
juanchito


2
मुझे लगता rotateहै कि सही शब्द है, नहीं shift
23

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
भविष्य के पाठकों के लिए: wiki.python.org/moin/TimeComplexitycollections.deque rotate()
Geoff

2
लेकिन ध्यान रहे, पहले deque.rotateकिसी dequeवस्तु में एक प्रकार के रूपांतरण की आवश्यकता होती है , जो इससे धीमी है l.append(l.pop(0))। इसलिए यदि आपके पास शुरू करने के लिए एक deque ऑब्जेक्ट है, तो सुनिश्चित करें कि यह सबसे तेज़ है। अन्यथा, उपयोग करें l.append(l.pop(0))
पुरेलल

8
विस्तृत करने के लिए, deque.rotateO (k) है लेकिन सूची से deque में टाइप रूपांतरण O (n) है । इसलिए यदि आप एक सूची से शुरू करते हैं, तो deque.rotate का उपयोग O (n) + O (k) = O (n) है। l.append(l.pop(0))दूसरी ओर O (1) है।
पुरेलल

3
@Purrell, सामने वाले आइटम को पॉप करना O (n) है। Wiki.python.org/moin/TimeComplexity में इसे O (k) के रूप में सूचीबद्ध किया गया है, और कश्मीर पॉपअप आइटम के बाद सूची में तत्वों की संख्या है, क्योंकि डेटा संरचना सूची के सामने की ओर सभी निम्नलिखित तत्वों को स्थानांतरित करती है। केवल अंतिम तत्व को इस कारण O (1) समय में पॉप किया जा सकता है।
किर्क बॉयर

88

केवल उपयोग करने के बारे में क्या pop(0)?

list.pop([i])

सूची में दिए गए स्थान पर आइटम निकालें, और इसे वापस लौटा दें। यदि कोई सूचकांक निर्दिष्ट नहीं है, a.pop()तो सूची में अंतिम आइटम को हटा और वापस कर देता है। ( iविधि हस्ताक्षर में चारों ओर वर्ग कोष्ठक निरूपित करते हैं कि पैरामीटर वैकल्पिक है, न कि आपको उस स्थिति में वर्ग कोष्ठक टाइप करना चाहिए। आप पायथन लाइब्रेरी संदर्भ में यह अंकन अक्सर देखेंगे।)


16
लेकिन क्या उस सूची के प्रत्येक तत्व को हटाने के लिए O (k) का खर्च नहीं होगा जहां k शेष तत्वों की संख्या है। तो कुल समय O (n ^ 2) wiki.python.org/moin/TimeComplexity
प्रमोद

5
यह वास्तव में इस सवाल का जवाब नहीं देता है। प्रश्न ऑर्डर में आइटम वापस करने के बारे में नहीं है, बल्कि एक नई सूची बनाने के बारे में है जो एक अलग क्रम में है।
user650261

5
नहीं, पॉप का उपयोग करते हुए प्रश्न का उत्तर होगा l.append(l.pop(0)। अगर मैं गलत नहीं हूँ तो O (1) है।
पुरेलल

4
list.pop आंतरिक रूप से list_ass_slice को कॉल करता है जो बहुत सारे आइटम को बहुत तेज़ी से स्थानांतरित करने के लिए मेमोव का उपयोग करता है, लेकिन यह अभी भी O (n) है। देखें github.com/python/cpython/blob/master/Objects/listobject.c और wiki.python.org/moin/TimeComplexity । निरंतर समय में अजगर सूची से हटाया जा सकता है कि केवल एक आइटम है।
DRAYX

2
Downvoted। Docs.python.org/3/tutorial/… से एक कतार के रूप में एक सूची का उपयोग करना भी संभव है, जहां पहला तत्व जोड़ा गया पहला तत्व प्राप्त किया गया है ("पहला-पहला, पहला-आउट"); हालाँकि, सूचियाँ इस उद्देश्य के लिए कुशल नहीं हैं। जबकि सूची के अंत से एप्स और पॉप तेज होते हैं, सूची की शुरुआत से आवेषण या पॉप करना धीमा होता है (क्योंकि अन्य सभी तत्वों को एक से स्थानांतरित करना पड़ता है)।
सांताएक्सएल

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
एसओ के बारे में मुझे जो अच्छा लगता है, वह यह है कि कभी-कभी नीचे दिए गए उत्तरों से आपको कुछ बेहतरीन नए खजाने मिल सकते हैं जैसे :)
noamgot

यह, जब मैंने इसका परीक्षण किया, तो बहुत धीमी गति से
पीटर हैरिसन

@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
NB: यह खाली सूची के लिए दुर्घटनाग्रस्त हो जाएगा।
मेवप्लप

n = n% len (seq) वापसी = seq [-n:] + seq [: - n]
user3303020

क्या आप समझा सकते हैं कि n = n% len (seq) क्यों?
एरीस

16

सबसे सरल तरीका जो मैं सोच सकता हूं:

a.append(a.pop(0))

3
यह सूचियों का सबसे तेज़ तरीका है। collections.dequeतेजी से लेकिन एक एकल पुनरावृत्ति पर सूची की लंबाई के अधिकांश सामान्य मामलों के लिए, या कई पुनरावृत्तियों के किसी भी मामले के a.append(a.pop(0))लिए, हिरण के प्रकार रूपांतरण की तुलना में तेजी से होने जा रहा है
Purrell

@runDOSrun इस प्रश्न का सही उत्तर है जो दुःख के रूप में दुःखद है । शायद आप इसे फिर से खोलने के लिए मतदान करेंगे?
वुल्फ

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

यह इस बात पर भी निर्भर करता है कि आप सूची को जगह में बदलना चाहते हैं (इसे बदलकर), या यदि आप चाहते हैं कि फ़ंक्शन नई सूची लौटाए। क्योंकि, मेरे परीक्षणों के अनुसार, आपके क्रियान्वयन की तुलना में कुछ ऐसा कम से कम बीस गुना तेज है जो दो सूचियों को जोड़ता है:

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

वास्तव में, यहां तक l = l[:]कि पास की गई सूची की एक प्रति पर काम करने के लिए उसमें से एक को जोड़ना अभी भी दोगुना तेज़ है।

Http://gist.github.com/288272 पर कुछ समय के साथ विभिन्न कार्यान्वयन


3
इसके बदले l[:n] = []मैं जाऊंगा del l[:n]। बस एक विकल्प है।
tzot

1
ओह, हाँ, अच्छा पुराना डेल। मैं अक्सर डेल के बारे में भूल जाता हूं; सूची संचालन एक कथन है, एक विधि नहीं। क्या py3k ने उस quirk को बदल दिया, या अभी भी हमें मिल गया है?
केटर्न २ k

2
@keturn: Py3 delमें अभी भी एक बयान है। हालाँकि x.__delitem__(y) <==> del x[y], यदि आप विधियों का उपयोग करना पसंद करते हैं, तो l.__delitem__(slice(n))भी बराबर है और 2 और 3 में काम करता है
Martineau

9

समय पर कुछ नोट:

यदि आप एक सूची से शुरू कर रहे हैं, l.append(l.pop(0))तो सबसे तेज़ तरीका है जिसका आप उपयोग कर सकते हैं। यह अकेले समय जटिलता के साथ दिखाया जा सकता है:

  • deque.rotate O (k) (k = तत्वों की संख्या) है
  • रूपांतरण की सूची हे (n) है
  • list.append और list.pop दोनों O (1) हैं

इसलिए यदि आप dequeवस्तुओं से शुरू कर रहे हैं , तो आप deque.rotate()ओ (के) की कीमत पर कर सकते हैं । लेकिन, यदि प्रारंभिक बिंदु एक सूची है, तो उपयोग करने की समय जटिलता deque.rotate()O (n) है। l.append(l.pop(0)O (1) पर तेज है।

उदाहरण के लिए, यहाँ कुछ नमूने 1M पुनरावृत्तियों पर दिए गए हैं:

जिन तरीकों को टाइप रूपांतरण की आवश्यकता होती है:

  • deque.rotateविचित्र वस्तु के साथ: 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

यह दिखाते हुए कि सूचियों से देवता बनाना हे (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

यदि आपको डेक्स ऑब्जेक्ट बनाने की आवश्यकता है:

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)

यदि आपके पास पहले से ही कोई वस्तु है:

1M पुनरावृत्तियों @ 0.12380790710449219 सेकंड

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

यदि आपको nparrays बनाने की आवश्यकता है

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

यदि आपके पास पहले से ही nparrays है:

1M पुनरावृत्तियों @ 6.0491721630096436 सेकंड

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)

"जगह में शिफ्ट"

किसी प्रकार के रूपांतरण की आवश्यकता नहीं है

1M पुनरावृत्तियों @ 4.819645881652832 सेकंड

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

किसी प्रकार के रूपांतरण की आवश्यकता नहीं है

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) नहीं है । यह लंबाई की सूची के संबंध में रैखिक समय में चलता है। आप अपने टाइमटाइम सेटअप को संशोधित करके परीक्षण कर सकते हैं:l = [random.random() for i in range(100000)]
एमु

1
list.pop एक निरंतर समय ऑपरेशन नहीं है। list.pop O (k) समय में चलता है जहां k हटाए गए तत्व के तत्वों की संख्या है, इसलिए सूची। pop (0) O (n) है। आंतरिक रूप से, list.pop list_ass_slice का उपयोग करता है, जो आइटम का उपयोग करने के लिए मेमोव का उपयोग तेजी से करता है, जैसे कि आप कभी भी अजगर के साथ कर सकते हैं, लेकिन लंबी सूचियों के लिए अभी भी बहुत समय लगता है। देखें github.com/python/cpython/blob/master/Objects/listobject.c और wiki.python.org/moin/TimeComplexity
DRayX

समय के लिए धन्यवाद (और टिप्पणियाँ @emu)। तो क्या हम कह सकते हैं कि l.append(l.pop(0))छोटी सूचियों (लगभग 7 तत्वों) को एक-एक करके स्थानांतरित करने के लिए सबसे अच्छा प्रदर्शन है?
वोल्फ

फिर से, l.append(l.pop(0))एक उत्तर के रूप में संबंधित : यह प्रश्न एक डुप्लिकेट के रूप में बंद है। शायद आप इसे फिर से खोलने के लिए मतदान करेंगे?
वुल्फ

8

मुझे भी इसमें दिलचस्पी थी और परफ्लोट (मेरी एक छोटी परियोजना) के साथ सुझाए गए कुछ समाधानों की तुलना में ।

परिणाम यह निकला

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))उत्तर के रूप में संबंधित : यह प्रश्न डुप्लिकेट के रूप में बंद है। शायद आप इसे फिर से खोलने के लिए मतदान करेंगे?
वुल्फ

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

Arrays में सूचियों का ओवरहेड नहीं है।

जहाँ तक आपके पास शुद्ध सूचियाँ हैं, आपके पास जितना अच्छा है उतना ही अच्छा है जितना आप कर सकते हैं।


3

मुझे लगता है कि आप इसके लिए देख रहे हैं:

a.insert(0, x)

मैं प्रश्न और आपके उत्तर के बीच संबंध नहीं देखता हूं। क्या आप इसे समझा सकते हैं?
वुल्फ

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

सूची को छोटा करने और दो उप-सूचियों को संक्षिप्त करने की आपकी विधि रैखिक-समय के संचालन हैं। मैं पॉप का उपयोग करने का सुझाव दूंगा, जो एक निरंतर-समय ऑपरेशन है, उदाहरण के लिए:

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

2
अद्यतन: इसे एक बेहतर संदर्भ के रूप में लें: wiki.python.org/moin/TimeComplexity , collections.dequeueपॉप और एपेंडलेफ़्ट का उपयोग करें , जो दोनों O (1) op हैं। ऊपर मेरे पहले उत्तर में, प्रविष्टि O (n) है।
हेरफज़

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

शिफ्ट_क्लासलिस्ट () विधि समान कोड को मेरे x.insert (0, x.pop ()) - समाधान के रूप में निष्पादित करती है, अन्य सूची वर्ग से एक सूची है। अन्य सूची की सामग्री को MyClass.classlist सूची में पास करने के बाद, shift_classlist () को कॉल करने से अन्य सूची भी बदल जाती है:

CONSOLE OUTPUT:

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()यह mutates सूची और क्योंकि दोनों के नाम ही सूची वस्तु को देखें। दोनों नाम बदलते दिखाई देते हैं क्योंकि वे एक ही वस्तु के लिए सिर्फ उपनाम हैं। x.classlist = otherlist[:]सूची की एक प्रति असाइन करने के बजाय उपयोग करें ।
दान डी।

अरे वाह! आपका बहुत बहुत धन्यवाद! मैं वास्तव में नहीं जानता था और यह जानना वास्तव में अच्छा है! :)
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 का उपयोग कर सकते हैं। यह भाषा की गलती नहीं है कि आपने 12 लाइन फ़ंक्शन लिखा है जो O (n) है, जब आप सिर्फ "l.append (l.pop (0))" लिख सकते हैं जो कि निरंतर समय है।
पुरेल जूल

l.append (l.pop (0)) O (n) है (l.pop (0) को प्रत्येक तत्व को शिफ्ट करना है), इस प्रकार यदि आप m मानों को स्थानांतरित करना चाहते हैं तो जटिलता वास्तव में O (n * m) है। मेरे द्वारा प्रदान किए गए एल्गोरिथ्म की जटिलता हे (एन) की परवाह किए बिना पाली की संख्या। व्यवहार में, यह धीमा है क्योंकि सी के बजाय अजगर ऑप्स में इतना तर्क किया जाता है (सूची। पीपी को सी में लागू किया गया है, देखें github.com/python/cpython/blob/master/Objects-listobject.c )।
DRAYX

1

मेरी भी ऐसी ही बात है। उदाहरण के लिए, दो ...

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 है। डीक रोटेशन रोटेशन कमांड 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

फंक्शन कॉपियों की सूची एक टेम्पलिस्ट को भेजी जाती है, ताकि पॉप फ़ंक्शन मूल सूची को प्रभावित न करें:

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

प्रोग्रामिंग पर्ल (कॉलम 2) में जॉन बेंटले ने पदों द्वारा छोड़े गए एक- nसदिश वेक्टर को घुमाने के लिए एक सुरुचिपूर्ण और कुशल एल्गोरिदम का वर्णन xकिया है i:

आइए समस्या को व्यूह 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
वही ओपी के पास है। आपने सिर्फ नाम बदले और एक जोर डाला।
रुफुस वीएस

समारोह list_shiftअपने जवाब में कार्य करने के लिए समान है shift, मूल प्रश्न में तो यह वास्तविक प्रश्न का उत्तर नहीं है: "वहाँ एक बेहतर तरीका है?"
रुफुसवीस

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.