2012-04-22 20 views
9

पायथन में एक सूची से एक उपन्यास को पुनर्स्थापित करने का सबसे तेज़ तरीका क्या है?पायथन में sublist को पुनर्स्थापित करने का सबसे तेज़ तरीका

मान लें कि हमारे पास एक सूची L = [a,b,c,d,e,f,g,h] है, अब मैं [c,d,e] लेना चाहता हूं और इसे g सूची में डाल देना चाहता हूं। मैं यह तेजी से कैसे कर सकता हूं?

संपादित करें: दूसरे शब्दों में मैं एक समारोह है कि लिखने के लिए करना चाहते हैं:

  1. लंबाई एन एल से का अर्क एक sublist L_sub, L_temp
  2. छोड़ने
  3. एक दिया पर L_sub के आइटम सम्मिलित स्थिति मैं L_temp

में मुख्य प्रश्न मुझे लगता है कि कैसे यथासंभव शीघ्र सूची में एक सूची डालने के लिए है।

+5

तुम कैसे जानते हो कि सी, डी, ई आइटम आप ले जाना चाहते हैं? क्या वे निश्चित स्थिति हैं, या आप मूल्यों की जांच कर रहे हैं? –

+0

क्या होगा यदि उपन्यास सम्मिलन बिंदु को ओवरलैप करता है? –

+0

यह संभव नहीं है, @ lazyr का जवाब भी इसे रोकता है। – TTT

उत्तर

5

मुझे लगता ओपी इस inplace करना चाहती है।

ऑपरेशन को तेजी से बनाने की कुंजी सूचियों के निर्माण को कम करना और सूचियों को छोटा करना/विस्तार करना है। इसका मतलब है कि हमें हमेशा सूची सूचकांक के 1: 1 असाइनमेंट करने का प्रयास करना चाहिए, इसलिए L[i:i] = L[a:b] और L[a:b] = [] नहीं। insert और pop के साथ लूप का उपयोग करना और भी बदतर है, क्योंकि तब आप सूची को कई बार छोटा और लंबा करते हैं। Concatenating सूचियां भी खराब है क्योंकि आपको पहले प्रत्येक भाग के लिए एक सूची बनाना है और फिर प्रत्येक + के लिए एक बार बड़ी और बड़ी समेकित सूचियां बनाना है। चूंकि आप इसे "इनस्थल" करना चाहते हैं, इसलिए आपको जेनरेट की गई सूची को अंत में L[:] पर असाइन करना होगा।

# items: 0 | 1 2 3 | 4 5 6 7 | 8 9 
    #   a span1 b  span2  c 
    # pos:  1   4    8 

    # Result: 
    #   0 | 4 5 6 7 | 1 2 3 | 8 9 
    #   a  span2   span2 c 

पहले अवलोकन करें। यदि a = start, b = end = start + length, और c सम्मिलित स्थिति है, तो हम जिस ऑपरेशन को करना चाहते हैं वह | मार्करों पर कटौती करना है और span1 और span2 स्वैप करना है।लेकिन अगर b = start और c = end और a सम्मिलित स्थिति है, तो हम भीspan1 और span2 स्वैप करना चाहते हैं। तो हमारे कार्य में, हम केवल दो लगातार खंडों से निपटते हैं जिन्हें स्वैप किया जाना चाहिए।

हम पूरी तरह से नई सूचियां बनाने से नहीं बच सकते हैं, क्योंकि हमें सामानों को स्थानांतरित करते समय ओवरलैपिंग मानों को स्टोर करने की आवश्यकता है। हम कर सकते हैं, हालांकि एक अस्थायी सूची में स्टोर करने के लिए दो स्पैन चुनने के द्वारा, जितनी छोटी हो सके सूची को कम से कम बनाएं।

def inplace_shift(L, start, length, pos): 
    if pos > start + length: 
     (a, b, c) = (start, start + length, pos) 
    elif pos < start: 
     (a, b, c) = (pos, start, start + length) 
    else: 
     raise ValueError("Cannot shift a subsequence to inside itself") 
    if not (0 <= a < b < c <= len(L)): 
     msg = "Index check 0 <= {0} < {1} < {2} <= {3} failed." 
     raise ValueError(msg.format(a, b, c, len(L))) 

    span1, span2 = (b - a, c - b) 
    if span1 < span2: 
     tmp = L[a:b] 
     L[a:a + span2] = L[b:c] 
     L[c - span1:c] = tmp 
    else: 
     tmp = L[b:c] 
     L[a + span2:c] = L[a:b] 
     L[a:a + span2] = tmp 

कोस अपने समय में कोई त्रुटि की है लगता है, इसलिए मैं तर्क को सही (endstart और length से की गणना) के बाद अपने कोड के साथ उन्हें redid, और इन परिणामों कर रहे हैं, धीरे से करने के लिए सबसे तेजी से।

Nick Craig-Wood: 100 loops, best of 3: 8.58 msec per loop 
vivek: 100 loops, best of 3: 4.36 msec per loop 
PaulP.R.O. (deleted?): 1000 loops, best of 3: 838 usec per loop 
unbeli: 1000 loops, best of 3: 264 usec per loop 
lazyr: 10000 loops, best of 3: 44.6 usec per loop 

मैंने परीक्षण नहीं किया है कि अन्य किसी भी दृष्टिकोण से सही परिणाम मिलते हैं।

+0

आपके द्वारा पोस्ट किया गया पिछले संस्करण काम करता है, यह कोई नहीं करता: x = रेंज (10); inplace_shift (x, 2,3,0) रिटर्न [0, 1, 0, 1, 5, 6, 7, 8, 9], यह होना चाहिए [2, 3, 4, 0, 1, 5, 6, 7 , 8, 9]। – TTT

+1

@ टीटीटी निश्चित, इंडेंटेशन त्रुटि। –

+0

यह गलत परिणाम उत्पन्न करता है। अगर मैं 'inplace_shift (रेंज (10), 3, 2, 6) कहता हूं, 'मुझे' 0, 1, 2, 5, 3, 4, 6, 7, 8, 9] मिलता है। इसे '[0, 1, 2, 5, 6, 7, 3, 4, 8, 9]' –

2

मैं अजगर सबस्ट्रिंग साथ यह करना होगा

def subshift(L, start, end, insert_at): 
    temp = L[start:end] 
    L = L[:start] + L[end:] 
    return L[:insert_at] + temp + L[insert_at:] 

print subshift(['a','b','c','d','e','f','g','h'], 2, 5, 4) 

start और end सबस्ट्रिंग बाहर कटौती करने के लिए की स्थिति का उल्लेख (अंत में हमेशा की तरह अजगर शैली में गैर अनन्य है। insert_at स्थिति को सम्मिलित करने के लिए संदर्भित करता है फिर के बाद यह कटौती की गई है में वापस उप स्ट्रिंग।

मुझे लगता है कि यदि सबस्ट्रिंग एक चरित्र या दो लंबाई में के रूप में अच्छा अनुकूलित सी कोड है की तुलना में अधिक कर रहे हैं इस में यात्रा के साथ किसी भी समाधान की तुलना में तेजी हो जाएगा एच कर रहा हूँ भारी उठाना

1
>>> L = ['a','b','c','d','e','f','g','h'] 
>>> L[7:7] = L[2:5] 
>>> L[2:5] = [] 
>>> L 
['a', 'b', 'f', 'g', 'c', 'd', 'e', 'h'] 
+0

यदि आप 5: 7 को 2 डालने का प्रयास करेंगे तो यह गलत व्यवहार नहीं करेगा? दूसरा एल [2: 5] तब पहले एल [2: 5] – Kos

+0

की तुलना में एक अलग स्थान का संदर्भ देगा 'एल = रेंज (5) 'और उपशीर्षक' [3: 5]' से '0'; अपेक्षित '[3, 4, 0, 1, 2]' वास्तविक '[3, 4, 0, 3, 4]' – Kos

+0

यह अब तक जो पोस्ट किया गया है, उससे सबसे तेज़ दृष्टिकोण प्रतीत होता है, लेकिन दूसरी असाइनमेंट आवश्यकता में सूचकांक मैंने जो मामले का उल्लेख किया है, उसमें भी काम करने के लिए ऑफसेट होना चाहिए। – Kos

0
def shift(L,start,n,i): 
    return L[:start]+L[start+n:i]+L[start:start+n]+L[i:] 
2

की जाँच क्या हम अब तक मिल गया है:

कोड

def subshift(L, start, end, insert_at): 
    'Nick Craig-Wood' 
    temp = L[start:end] 
    L = L[:start] + L[end:] 
    return L[:insert_at] + temp + L[insert_at:] 

# (promising but buggy, needs correction; 
# see comments at unbeli's answer) 
def unbeli(x, start, end, at): 
    'unbeli' 
    x[at:at] = x[start:end] 
    x[start:end] = [] 

def subshift2(L, start, length, pos): 
    'PaulP.R.O.' 
    temp = pos - length 
    S = L[start:length+start] 
    for i in range(start, temp): 
     L[i] = L[i + length] 
    for i in range(0,length): 
     L[i + temp] = S[i] 
    return L 

def shift(L,start,n,i): 
    'vivek' 
    return L[:start]+L[start+n:i]+L[start:start+n]+L[i:] 

मानक:

> args = range(100000), 3000, 2000, 60000 

> timeit subshift(*args) 
100 loops, best of 3: 6.43 ms per loop 

    > timeit unbeli(*args) 
1000000 loops, best of 3: 631 ns per loop 

> timeit subshift2(*args) 
100 loops, best of 3: 11 ms per loop 

> timeit shift(*args) 
100 loops, best of 3: 4.28 ms per loop 
+0

आप दो अलग-अलग मामलों का परीक्षण कर रहे हैं। उपशीर्षक और अविश्वास में, आप तर्क का उपयोग कर रहे हैं, तर्क के रूप में अंत, जिसका अर्थ है कि आप जो टुकड़ा चला रहे हैं वह आपके द्वारा उपयोग किए जा रहे तर्कों के साथ खाली है। –

2

यहाँ एक वैकल्पिक inplace समाधान है:

def movesec(l,srcIndex,n,dstIndex): 
    if srcIndex+n>dstIndex: raise ValueError("overlapping indexes") 
    for i in range(n): 
     l.insert(dstIndex+1,l.pop(srcIndex)) 

    return l 


print range(10) 
print movesec(range(10),3,2,6)  

आउटपुट:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # orginal 
[0, 1, 2, 5, 6, 7, 3, 4, 8, 9] # modified 
+0

यह "इनस्थल" नहीं है। – unbeli

+0

@unbeli: ऐसा प्रतीत होता है। 'रिटर्न एल' पर टिप्पणी करने का प्रयास करें और इसे एक सूची के साथ कॉल करें। पहले और बाद में सूची की तुलना करें। क्या वह 'इनस्थल' नहीं है? मेरे पास सुविधा के रूप में 'वापसी एल' है ... –

संबंधित मुद्दे

 संबंधित मुद्दे