एकल सूची से जोड़े


98

अक्सर पर्याप्त, मुझे जोड़ों द्वारा एक सूची संसाधित करने की आवश्यकता मिली है। मैं सोच रहा था कि यह करने के लिए पायथोनिक और कुशल तरीका कौन सा होगा, और यह Google पर पाया गया:

pairs = zip(t[::2], t[1::2])

मैंने सोचा था कि यह काफी आकर्षक था, लेकिन हाल ही में मुहावरों बनाम दक्षता पर चर्चा के बाद , मैंने कुछ परीक्षण करने का फैसला किया:

import time
from itertools import islice, izip

def pairs_1(t):
    return zip(t[::2], t[1::2]) 

def pairs_2(t):
    return izip(t[::2], t[1::2]) 

def pairs_3(t):
    return izip(islice(t,None,None,2), islice(t,1,None,2))

A = range(10000)
B = xrange(len(A))

def pairs_4(t):
    # ignore value of t!
    t = B
    return izip(islice(t,None,None,2), islice(t,1,None,2))

for f in pairs_1, pairs_2, pairs_3, pairs_4:
    # time the pairing
    s = time.time()
    for i in range(1000):
        p = f(A)
    t1 = time.time() - s

    # time using the pairs
    s = time.time()
    for i in range(1000):
        p = f(A)
        for a, b in p:
            pass
    t2 = time.time() - s
    print t1, t2, t2-t1

मेरे कंप्यूटर पर ये परिणाम थे:

1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578

यदि मैं उन्हें सही ढंग से व्याख्या कर रहा हूं, तो इसका मतलब यह होना चाहिए कि पायथन में सूचियों, सूची अनुक्रमण और सूची स्लाइसिंग का कार्यान्वयन बहुत कुशल है। यह आराम और अप्रत्याशित दोनों का परिणाम है।

क्या जोड़ियों में किसी सूची को ट्रेस करने का एक और "बेहतर" तरीका है?

ध्यान दें कि यदि सूची में विषम संख्या में तत्व हैं, तो अंतिम किसी भी जोड़े में नहीं होगा।

यह सुनिश्चित करने का सही तरीका होगा कि सभी तत्व शामिल हैं?

मैंने इन दोनों सुझावों को परीक्षणों के उत्तरों से जोड़ा:

def pairwise(t):
    it = iter(t)
    return izip(it, it)

def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

ये परिणाम हैं:

0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176

अब तक के परिणाम

सबसे अजगर और बहुत कुशल:

pairs = izip(t[::2], t[1::2])

सबसे कुशल और बहुत अजगर:

pairs = izip(*[iter(t)]*2)

मुझे यह समझने में एक पल लगा कि पहला उत्तर दो पुनरावृत्तियों का उपयोग करता है जबकि दूसरा एकल का उपयोग करता है।

तत्वों की एक विषम संख्या के साथ अनुक्रम से निपटने के लिए, सुझाव मूल तत्व को बढ़ाने के लिए किया गया है जिसमें एक तत्व ( None) है जो पिछले अंतिम तत्व के साथ जोड़ा जाता है, जो कुछ हासिल किया जा सकता है itertools.izip_longest()

आखिरकार

ध्यान दें कि, पायथन 3.x में, zip()व्यवहार करता है itertools.izip()और itertools.izip() चला गया है।


पुन: "सही तरीका" - वहाँ एक "सही" तरीका नहीं है! यह उपयोग के मामले पर निर्भर करता है।
एंड्रयू जाफ

@Andrew Jaffe मैंने इस मामले में "सर्वश्रेष्ठ" के लिए मानदंड दिया: कुशल, और पायथोनिक।
अपाला

@ अपाला: मेरा मतलब है कि विषम संख्या होने का परिणाम उपयोग पर निर्भर करता है। उदाहरण के लिए: आप बस अंतिम तत्व को छोड़ सकते हैं, या एक विशिष्ट ज्ञात डमी तत्व जोड़ सकते हैं, या पिछले एक को डुप्लिकेट कर सकते हैं
एंड्रयू जफ

2
@ अपाला: क्योंकि आप timeitमॉड्यूल के बजाय कुछ मंबो-जंबो का उपयोग कर रहे हैं ।
साइलेंटगॉस्ट

1
n- डुप्लिकेट: बस एक त्वरित खोज में: stackoverflow.com/questions/4501636 , stackoverflow.com/questions/4170295 , stackoverflow.com/questions/434287
tokland

जवाबों:


52

मेरा पसंदीदा तरीका यह करना है:

from itertools import izip

def pairwise(t):
    it = iter(t)
    return izip(it,it)

# for "pairs" of any length
def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

जब आप सभी तत्वों की जोड़ी बनाना चाहते हैं, तो आपको स्पष्ट रूप से एक भरने की आवश्यकता हो सकती है:

from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
    it = iter(t)
    return izip_longest(*[it]*size, fillvalue=fillvalue)

लगता है कि पहला (जोड़ीदार) फंक्शन क्लोनिंग और दूसरे इटरेटर के आगे बढ़ने से चूक रहा है। itertoolsव्यंजनों अनुभाग देखें ।
अपाला

@ अपाला: जिप एक ही पुनरावृत्त को दो बार अग्रिम करता है।
जोचेन रिट्जेल

बेशक, आप सही हैं, और जोड़ीदार अब तक सबसे कुशल है, मुझे नहीं पता कि क्यों।
अपालाला

1
मुझे यह समाधान पसंद है: यह आलसी है, और यह पुनरावृत्तियों की महान प्रभाव का शोषण करता है। आप इसे पठनीयता की कीमत पर शायद वन-लाइनर भी बना सकते हैं:izip(*[iter(t)]*size)
मूर

अपने दूसरे समाधान के लिए, क्या आप प्रदर्शन के बाद जाने वाली सूची बनाने से बचना चाहेंगे?
अधिकतम

41

मैं कहूंगा कि आपका प्रारंभिक समाधान pairs = zip(t[::2], t[1::2])सबसे अच्छा है क्योंकि इसे पढ़ना सबसे आसान है (और पायथन 3 में, zipस्वचालित रूप से एक सूची के बजाय एक पुनरावृत्त लौटाता है)।

यह सुनिश्चित करने के लिए कि सभी तत्व शामिल हैं, आप बस द्वारा सूची का विस्तार कर सकते हैं None

फिर, यदि सूची में विषम संख्या में तत्व हैं, तो अंतिम जोड़ी होगी (item, None)

>>> t = [1,2,3,4,5]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, None)]
>>> t = [1,2,3,4,5,6]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, 6)]

6

मैं छोटे अस्वीकरण से शुरू करता हूं - नीचे दिए गए कोड का उपयोग न करें। यह पाइथोनिक नहीं है, मैंने सिर्फ मनोरंजन के लिए लिखा है। यह @ THC4k pairwiseफ़ंक्शन के समान है, लेकिन यह उपयोग करता है iterऔर lambdaबंद होता है। यह itertoolsमॉड्यूल का उपयोग नहीं करता है और समर्थन नहीं करता है fillvalue। मैंने इसे यहाँ रखा क्योंकि किसी को यह दिलचस्प लग सकता है:

pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)

4

जहाँ तक अधिकांश पाइथोनिक जाता है, मैं कहता हूँ कि पाइथन स्रोत डॉक्स में प्रदत्त व्यंजनों में से कुछ (जिनमें से कई उत्तर जैसे कि @JochenRitzel प्रदान करते हैं) शायद आपकी सबसे अच्छी शर्त है;)

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

आधुनिक अजगर पर आपको बस zip_longest(*args, fillvalue=fillvalue) इसी डॉक्टर पृष्ठ के अनुसार उपयोग करना होगा


2

क्या जोड़ियों में किसी सूची को ट्रेस करने का एक और "बेहतर" तरीका है?

मैं निश्चित रूप से नहीं कह सकता, लेकिन मुझे इसमें संदेह है: किसी भी अन्य ट्रैवर्सल में अधिक पायथन कोड शामिल होगा जिसकी व्याख्या की जानी है। जिप () जैसे बिल्ट-इन फ़ंक्शंस C में लिखे गए हैं जो बहुत तेज़ है।

यह सुनिश्चित करने का सही तरीका होगा कि सभी तत्व शामिल हैं?

सूची की लंबाई जांचें और यदि यह विषम है ( len(list) & 1 == 1), तो सूची को कॉपी करें और किसी आइटम को जोड़ें।


2
>>> my_list = [1,2,3,4,5,6,7,8,9,10]
>>> my_pairs = list()
>>> while(my_list):
...     a = my_list.pop(0); b = my_list.pop(0)
...     my_pairs.append((a,b))
... 
>>> print(my_pairs)
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]

IndexError: रिक्त सूची से पॉप
मुख्यालय

@HQuser ज़रूर, अगर आपको सूची में आइटम की विषम संख्या है तो आपको वह त्रुटि मिलेगी। आपको यह सुनिश्चित करने के लिए जानना होगा कि आपके पास इस त्रुटि स्थिति के लिए जोड़े हैं या जाँच करें।
वाटरमूलेक्यूल


0

यहां एक जनरेटर का उपयोग करके जोड़े / पैर बनाने का एक उदाहरण है। जनरेटर स्टैक सीमा से मुक्त हैं

def pairwise(data):
    zip(data[::2], data[1::2])

उदाहरण:

print(list(pairwise(range(10))))

आउटपुट:

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

निष्पादन समय की तुलना?
एलन

सूची को जोड़े में नहीं तोड़ा जाता है, क्योंकि मूल सूची में अधिकांश संख्या दो ट्यूपल्स में दिखाई देती है। अपेक्षित उत्पादन है[(0, 1), (2, 3), (4, 5)....
अपाला

@ अपाला ने इशारा करते हुए धन्यवाद दिया। मैंने सही आउटपुट प्रदान करने के लिए कोड तय किया
व्लाद बेजेन

zip()पहले से ही Python 3.x, @VladBezden
Apalala

-1

अगर किसी को उत्तर के लिए एल्गोरिथ्म-वार की आवश्यकता होती है, तो यह है:

>>> def getPairs(list):
...     out = []
...     for i in range(len(list)-1):
...         a = list.pop(0)
...         for j in a:
...             out.append([a, j])
...     return b
>>> 
>>> k = [1, 2, 3, 4]
>>> l = getPairs(k)
>>> l
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

लेकिन ध्यान दें कि आपकी मूल सूची भी इसके अंतिम तत्व तक कम हो जाएगी, क्योंकि आपने इसका उपयोग popकिया था।

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