अधिकांश पायथोनिक तरीका दो तारों को इंटरलेव करने के लिए


115

दो तारों को एक साथ मिलाने का सबसे पैथोनिक तरीका क्या है?

उदाहरण के लिए:

इनपुट:

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

आउटपुट:

'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

2
यहाँ उत्तर ने मोटे तौर पर मान लिया है कि आपके दो इनपुट तार समान लंबाई के होंगे। क्या यह एक सुरक्षित धारणा है या क्या आपको इसे संभालने की आवश्यकता है?
सुपरबीसमैन

@SuperBiasedMan यह देखने के लिए उपयोगी हो सकता है कि यदि आपके पास समाधान है तो सभी स्थितियों को कैसे संभालना है। यह प्रश्न के लिए प्रासंगिक है, लेकिन विशेष रूप से मेरे मामले में नहीं।
ब्रेंडन देव

3
@drexx शीर्ष उत्तरदाता ने वैसे भी इसके लिए एक समाधान के साथ टिप्पणी की, इसलिए मैंने इसे अपने पोस्ट में संपादित किया, इसलिए यह व्यापक है।
SuperBiasedMan

जवाबों:


127

मेरे लिए, सबसे पाइथोनिक * तरीका निम्नलिखित है जो बहुत अधिक एक ही काम करता है लेकिन +प्रत्येक स्ट्रिंग में अलग-अलग वर्णों को संक्षिप्त करने के लिए ऑपरेटर का उपयोग करता है :

res = "".join(i + j for i, j in zip(u, l))
print(res)
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

यह दो join()कॉल का उपयोग करने से भी तेज है :

In [5]: l1 = 'A' * 1000000; l2 = 'a' * 1000000

In [6]: %timeit "".join("".join(item) for item in zip(l1, l2))
1 loops, best of 3: 442 ms per loop

In [7]: %timeit "".join(i + j for i, j in zip(l1, l2))
1 loops, best of 3: 360 ms per loop

तेजी से दृष्टिकोण मौजूद हैं, लेकिन वे अक्सर कोड को बाधित करते हैं।

नोट: यदि दो इनपुट स्ट्रिंग्स समान लंबाई नहीं हैं , तो zipछोटी स्ट्रिंग के अंत में पुनरावृति को रोकने के लिए लंबे समय तक एक को छोटा किया जाएगा । इस मामले में zipएक के बजाय मॉड्यूल से zip_longest( izip_longestपायथन 2 में) का उपयोग करना चाहिए itertoolsताकि यह सुनिश्चित हो सके कि दोनों तार पूरी तरह से समाप्त हो गए हैं।


* पायथन के ज़ेन से एक उद्धरण लेने के लिए : पठनीयता मायने रखती है
पाइथोनिक = मेरे लिए पठनीयता ; i + jकम से कम मेरी आंखों के लिए बस नेत्रहीन रूप से अधिक आसानी से पार्स किया गया है।


1
एन स्ट्रिंग्स के लिए कोडिंग प्रयास ओ (एन) है, हालांकि। फिर भी, यह तब तक अच्छा है जब तक n छोटा है।
टाइगरहॉक 3

आपका जनरेटर संभवतः जुड़ने की तुलना में अधिक उपरि पैदा कर रहा है।
पडेरिक कनिंघम

5
रन "".join([i + j for i, j in zip(l1, l2)])और यह निश्चित रूप से सबसे तेज़ होगा
पैडरिक कनिंघम

6
"".join(map("".join, zip(l1, l2)))यह और भी तेज है, हालांकि जरूरी नहीं कि अधिक पाइथोनिक हो।
हेंसी तोहारामो

63

तेजी से वैकल्पिक

दूसरा रास्ता:

res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
print(''.join(res))

आउटपुट:

'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

गति

ऐसा लगता है कि यह तेज है:

%%timeit
res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
''.join(res)

100000 loops, best of 3: 4.75 µs per loop

अब तक के सबसे तेज समाधान की तुलना में:

%timeit "".join(list(chain.from_iterable(zip(u, l))))

100000 loops, best of 3: 6.52 µs per loop

इसके अलावा बड़े तार के लिए:

l1 = 'A' * 1000000; l2 = 'a' * 1000000

%timeit "".join(list(chain.from_iterable(zip(l1, l2))))
1 loops, best of 3: 151 ms per loop


%%timeit
res = [''] * len(l1) * 2
res[::2] = l1
res[1::2] = l2
''.join(res)

10 loops, best of 3: 92 ms per loop

पायथन 3.5.1।

विभिन्न लंबाई के साथ तार के लिए भिन्नता

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijkl'

छोटा एक निर्धारित लंबाई ( zip()समतुल्य)

min_len = min(len(u), len(l))
res = [''] * min_len * 2 
res[::2] = u[:min_len]
res[1::2] = l[:min_len]
print(''.join(res))

आउटपुट:

AaBbCcDdEeFfGgHhIiJjKkLl

लंबे समय तक एक निर्धारित लंबाई ( itertools.zip_longest(fillvalue='')बराबर)

min_len = min(len(u), len(l))
res = [''] * min_len * 2 
res[::2] = u[:min_len]
res[1::2] = l[:min_len]
res += u[min_len:] + l[min_len:]
print(''.join(res))

आउटपुट:

AaBbCcDdEeFfGgHhIiJjKkLlMNOPQRSTUVWXYZ

49

के साथ join()और zip()

>>> ''.join(''.join(item) for item in zip(u,l))
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

17
या''.join(itertools.chain.from_iterable(zip(u, l)))
ब्लेंडर

1
यह एक सूची को छोटा कर देगा यदि कोई दूसरे से छोटा है, तो zipरुक जाता है जब छोटी सूची पूरी तरह से खत्म हो गई है।
सुपरबीसमैन

5
@SuperBiasedMan - हां। itertools.zip_longestअगर यह एक मुद्दा बन जाता है तो इसका इस्तेमाल किया जा सकता है।
टाइगरहॉक 3

18

अजगर 2 पर, द्वारा अब तक तेजी से जिस तरह से चीजें, छोटे तार के लिए सूची टुकड़ा करने की क्रिया और ~ लंबे लोगों के लिए 30x की गति करने के लिए ~ 3x पर, है

res = bytearray(len(u) * 2)
res[::2] = u
res[1::2] = l
str(res)

हालांकि यह पायथन 3 पर काम नहीं करेगा। आप कुछ इस तरह से लागू कर सकते हैं

res = bytearray(len(u) * 2)
res[::2] = u.encode("ascii")
res[1::2] = l.encode("ascii")
res.decode("ascii")

लेकिन तब तक आप पहले से ही छोटे तार के लिए सूचीकरण से अधिक लाभ खो चुके हैं (यह अभी भी 20x लंबी स्ट्रिंग के लिए गति है) और यह अभी तक गैर-एएससीआईआई पात्रों के लिए भी काम नहीं करता है।

FWIW, यदि आप बड़े पैमाने पर स्ट्रिंग्स पर यह कर रहे हैं और हर चक्र की आवश्यकता है, और किसी कारण से पायथन स्ट्रिंग्स का उपयोग करना है ... यहाँ यह कैसे करना है:

res = bytearray(len(u) * 4 * 2)

u_utf32 = u.encode("utf_32_be")
res[0::8] = u_utf32[0::4]
res[1::8] = u_utf32[1::4]
res[2::8] = u_utf32[2::4]
res[3::8] = u_utf32[3::4]

l_utf32 = l.encode("utf_32_be")
res[4::8] = l_utf32[0::4]
res[5::8] = l_utf32[1::4]
res[6::8] = l_utf32[2::4]
res[7::8] = l_utf32[3::4]

res.decode("utf_32_be")

विशेष-छोटे प्रकार के सामान्य मामले को भी मदद मिलेगी। एफडब्ल्यूआईडब्ल्यू, यह लंबी स्ट्रिंग्स के लिए सूची स्लाइसिंग की केवल 3x गति और छोटे स्ट्रिंग्स के लिए 4 से 5 धीमी का कारक है ।

किसी भी तरह से मैं joinसमाधान पसंद करता हूं , लेकिन चूंकि समय का उल्लेख कहीं और किया गया था, इसलिए मुझे लगा कि मैं इसमें शामिल हो सकता हूं।


16

यदि आप सबसे तेज़ तरीका चाहते हैं, तो आप itertools के साथ जोड़ सकते हैंoperator.add :

In [36]: from operator import add

In [37]: from itertools import  starmap, izip

In [38]: timeit "".join([i + j for i, j in uzip(l1, l2)])
1 loops, best of 3: 142 ms per loop

In [39]: timeit "".join(starmap(add, izip(l1,l2)))
1 loops, best of 3: 117 ms per loop

In [40]: timeit "".join(["".join(item) for item in zip(l1, l2)])
1 loops, best of 3: 196 ms per loop

In [41]:  "".join(starmap(add, izip(l1,l2))) ==  "".join([i + j   for i, j in izip(l1, l2)]) ==  "".join(["".join(item) for item in izip(l1, l2)])
Out[42]: True

लेकिन संयोजन izipऔरchain.from_iterable फिर से तेज है

In [2]: from itertools import  chain, izip

In [3]: timeit "".join(chain.from_iterable(izip(l1, l2)))
10 loops, best of 3: 98.7 ms per loop

वहाँ भी बीच बहुत अधिक अंतर है chain(*औरchain.from_iterable(...

In [5]: timeit "".join(chain(*izip(l1, l2)))
1 loops, best of 3: 212 ms per loop

ज्वाइन के साथ जेनरेटर जैसी कोई चीज नहीं है, पासिंग हमेशा धीमी होती जा रही है क्योंकि अजगर पहले कंटेंट का इस्तेमाल करते हुए एक लिस्ट बनाएगा क्योंकि यह डेटा के ऊपर से दो पास करता है, एक को साइज का पता लगाना होता है और एक को असल में करना होता है। जो एक जनरेटर का उपयोग करना संभव नहीं होगा:

join.h :

 /* Here is the general case.  Do a pre-pass to figure out the total
  * amount of space we'll need (sz), and see whether all arguments are
  * bytes-like.
   */

यदि आपके पास अलग-अलग लंबाई के तार हैं और आप डेटा नहीं खोना चाहते हैं तो आप izip_longest का उपयोग कर सकते हैं :

In [22]: from itertools import izip_longest    
In [23]: a,b = "hlo","elworld"

In [24]:  "".join(chain.from_iterable(izip_longest(a, b,fillvalue="")))
Out[24]: 'helloworld'

अजगर 3 के लिए इसे कहा जाता है zip_longest

लेकिन python2 के लिए, वेद्रेक का सुझाव अब तक का सबसे तेज़ है:

In [18]: %%timeit
res = bytearray(len(u) * 2)
res[::2] = u
res[1::2] = l
str(res)
   ....: 
100 loops, best of 3: 2.68 ms per loop

2
क्यों list?? अनलाइडेड है
कॉपरफील्ड

1
मेरे परीक्षणों के अनुसार नहीं, आप मध्यस्थ सूची बनाने में समय गंवाते हैं और पुनरावृत्तियों का उपयोग करने के उद्देश्य को पराजित करते हैं। "".join(list(...))मुझे समय देने के लिए 6.715280318699769 और मुझे समय "".join(starmap(...))देने के लिए 6.46332361384313
कॉपरफील्ड

1
फिर क्या, मशीन निर्भर है ?? कोई फर्क नहीं पड़ता क्योंकि मैं जहां भी परीक्षण चलाता हूं, मुझे वही सटीक परिणाम मिलता है, जिसकी "".join(list(starmap(add, izip(l1,l2))))तुलना में धीमी है "".join(starmap(add, izip(l1,l2)))। मैं अपनी मशीन में अजगर 2.7.11 में और अजगर 3.5.1 में भी www.python.org के वर्चुअल कंसोल में अजगर 3.4.3 के साथ दौड़ता हूं और सभी यही कहते हैं और मैं इसे एक-दो बार चलाता हूं और हमेशा वही
कॉपरफील्ड

मैं पढ़ता हूं और जो मैं देखता हूं वह यह है कि यह अपने बफर चर में हर समय आंतरिक रूप से एक सूची बनाता है, भले ही आप इसके पास से गुजरते हों, इसलिए NO को इसका एक कारण यह सूची देना है
कॉपरफील्ड

@Copperfield, क्या आप सूची कॉल या सूची पास करने के बारे में बात कर रहे हैं?
पादरिक कनिंघम

12

आप इसका उपयोग भी कर सकते हैं mapऔर operator.add:

from operator import add

u = 'AAAAA'
l = 'aaaaa'

s = "".join(map(add, u, l))

आउटपुट :

'AaAaAaAaAa'

मैप क्या करता है, यह प्रत्येक तत्व को पहली पुनरावृत्ति से लेता है uऔर दूसरे पुनरावृत्ति से पहले तत्वों lको पहले तर्क के रूप में दिए गए फ़ंक्शन को लागू करता है add। फिर जुड़ते हैं बस उनसे जुड़ते हैं।


9

जिम का जवाब बहुत अच्छा है, लेकिन यहाँ मेरा पसंदीदा विकल्प है, अगर आपको कुछ आयातों से ऐतराज नहीं है:

from functools import reduce
from operator import add

reduce(add, map(add, u, l))

7
उन्होंने कहा कि अधिकांश पाइथोनिक, अधिकांश हास्केलिक नहीं;)
कर्ट

7

इनमें से बहुत सारे सुझाव यह मानते हैं कि तार समान लंबाई के हैं। हो सकता है कि यह सभी उचित उपयोग के मामलों को कवर करता हो, लेकिन कम से कम मुझे ऐसा लगता है कि आप अलग-अलग लंबाई के तारों को भी जोड़ना चाह सकते हैं। या मैं केवल एक ही सोच रहा हूँ कि मेष को इस तरह से काम करना चाहिए:

u = "foobar"
l = "baz"
mesh(u,l) = "fboaozbar"

ऐसा करने का एक तरीका निम्नलिखित होगा:

def mesh(a,b):
    minlen = min(len(a),len(b))
    return "".join(["".join(x+y for x,y in zip(a,b)),a[minlen:],b[minlen:]])

5

मुझे दो forएस का उपयोग करना पसंद है , चर नाम एक संकेत / अनुस्मारक दे सकता है कि क्या हो रहा है:

"".join(char for pair in zip(u,l) for char in pair)

4

बस एक और, अधिक मूल दृष्टिकोण जोड़ने के लिए:

st = ""
for char in u:
    st = "{0}{1}{2}".format( st, char, l[ u.index( char ) ] )

4

O- (1) प्रयास के साथ n स्ट्रिंग को संभालने के लिए यहां डबल-लिस्ट-कॉम्प्रिहेंशन उत्तर पर विचार नहीं करने के लिए थोड़ा अन-पायथोनिक लगता है:

"".join(c for cs in itertools.zip_longest(*all_strings) for c in cs)

जहाँ all_stringsआप में हस्तक्षेप करने के लिए चाहते तार की एक सूची है। आपके मामले में, all_strings = [u, l]। एक पूर्ण उपयोग उदाहरण इस तरह दिखेगा:

import itertools
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b = 'abcdefghijklmnopqrstuvwxyz'
all_strings = [a,b]
interleaved = "".join(c for cs in itertools.zip_longest(*all_strings) for c in cs)
print(interleaved)
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

कई जवाबों की तरह, सबसे तेज़? शायद नहीं, लेकिन सरल और लचीला। इसके अलावा, बहुत अधिक जटिल जटिलता के बिना, यह स्वीकृत उत्तर की तुलना में थोड़ा तेज है (सामान्य तौर पर, अजगर में स्ट्रिंग जोड़ थोड़ा धीमा है):

In [7]: l1 = 'A' * 1000000; l2 = 'a' * 1000000;

In [8]: %timeit "".join(a + b for i, j in zip(l1, l2))
1 loops, best of 3: 227 ms per loop

In [9]: %timeit "".join(c for cs in zip(*(l1, l2)) for c in cs)
1 loops, best of 3: 198 ms per loop

सबसे तेज़ उत्तर के रूप में अभी भी उतना तेज़ नहीं है, हालांकि: जो इसी डेटा और कंप्यूटर पर 50.3 एमएस मिला है
स्कोरर

3

वर्तमान अग्रणी समाधान की तुलना में संभावित रूप से तेज़ और कम:

from itertools import chain

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

res = "".join(chain(*zip(u, l)))

रणनीति गति-वार सी-लेवल पर अधिक से अधिक संभव है। समान zip_longest () असमान तारों के लिए ठीक है और यह चेन () के रूप में एक ही मॉड्यूल से बाहर आ जाएगा, इसलिए मुझे वहां बहुत अधिक अंक नहीं दे सकते हैं!

अन्य समाधान जो मैं रास्ते में आया था:

res = "".join(u[x] + l[x] for x in range(len(u)))

res = "".join(k + l[i] for i, k in enumerate(u))

3

आप 1 का उपयोग कर सकते हैंiteration_utilities.roundrobin

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

from iteration_utilities import roundrobin
''.join(roundrobin(u, l))
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

या एक ManyIterablesही पैकेज से वर्ग:

from iteration_utilities import ManyIterables
ManyIterables(u, l).roundrobin().as_string()
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

1 यह एक तीसरे पक्ष के पुस्तकालय से है जिसे मैंने लिखा है iteration_utilities:।


2

मैं पढ़ने योग्य और आसान तरीका पाने के लिए जिप () का उपयोग करूंगा:

result = ''
for cha, chb in zip(u, l):
    result += '%s%s' % (cha, chb)

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