İki dizgiyi birbirine bağlamanın en pitonik yolu nedir?
Örneğin:
Giriş:
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
Çıktı:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
İki dizgiyi birbirine bağlamanın en pitonik yolu nedir?
Örneğin:
Giriş:
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
Çıktı:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
Yanıtlar:
Benim için en pitonik * yol, hemen hemen aynı şeyi yapan, ancak +
her dizedeki ayrı karakterleri birleştirmek için operatörü kullanan şudur :
res = "".join(i + j for i, j in zip(u, l))
print(res)
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
Ayrıca iki join()
çağrı kullanmaktan daha hızlıdır :
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
Daha hızlı yaklaşımlar vardır, ancak bunlar genellikle kodu karıştırır.
Not: İki giriş dizisi aynı uzunlukta değilse , daha uzun zip
olan, daha kısa dizinin sonunda yinelenen duraklar olarak kesilecektir . Bu durumda , her iki dizenin de tamamen tükendiğinden emin olmak için modülden zip
biri yerine zip_longest
( izip_longest
Python 2'de) kullanılmalıdır itertools
.
* Zen of Python'dan bir alıntı yapmak gerekirse : Okunabilirlik önemlidir .
Pythonic = benim için okunabilirlik ; i + j
en azından gözlerim için görsel olarak daha kolay ayrıştırılıyor.
"".join([i + j for i, j in zip(l1, l2)])
ve kesinlikle en hızlı olacak
"".join(map("".join, zip(l1, l2)))
daha pitonik olmasa da daha hızlıdır.
Diğer yol:
res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
print(''.join(res))
Çıktı:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
Daha hızlı gibi görünüyor:
%%timeit
res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
''.join(res)
100000 loops, best of 3: 4.75 µs per loop
şimdiye kadarki en hızlı çözümden daha fazla:
%timeit "".join(list(chain.from_iterable(zip(u, l))))
100000 loops, best of 3: 6.52 µs per loop
Ayrıca daha büyük dizeler için:
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
Python 3.5.1.
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijkl'
zip()
eşdeğer)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))
Çıktı:
AaBbCcDdEeFfGgHhIiJjKkLl
itertools.zip_longest(fillvalue='')
eşdeğer)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))
Çıktı:
AaBbCcDdEeFfGgHhIiJjKkLlMNOPQRSTUVWXYZ
İle join()
ve zip()
.
>>> ''.join(''.join(item) for item in zip(u,l))
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
''.join(itertools.chain.from_iterable(zip(u, l)))
zip
, daha kısa liste tamamen yinelendiğinde duracağı gibi , bir listeyi kesecektir.
itertools.zip_longest
bir sorun haline gelirse kullanılabilir.
Python 2'de işleri yapmanın çok daha hızlı yolu, küçük dizeler için liste dilimlemenin ~ 3 katı ve uzun dizeler için ~ 30 kat daha hızlıdır.
res = bytearray(len(u) * 2)
res[::2] = u
res[1::2] = l
str(res)
Yine de bu Python 3'te çalışmaz. Gibi bir şey uygulayabilirsin
res = bytearray(len(u) * 2)
res[::2] = u.encode("ascii")
res[1::2] = l.encode("ascii")
res.decode("ascii")
ancak o zamana kadar, küçük dizgiler için liste dilimlemenin kazançlarını çoktan kaybettiniz (uzun dizelerin hızının hala 20 katıdır) ve bu henüz ASCII olmayan karakterler için bile işe yaramıyor.
FWIW, eğer edilmektedir masif dizeleri bu yapıyor ve her devirde ihtiyaç ve nedense Python dizeleri kullanmak zorunda ... Burada bunu nasıl açıklanmıştır:
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")
Daha küçük türlerin ortak durumunu özel kasaya koymak da yardımcı olacaktır. FWIW, bu, uzun dizeler için liste dilimleme hızının yalnızca 3 katı ve küçük dizeler için 4 ila 5 arasında daha yavaş bir faktördür .
Her iki durumda da join
çözümleri tercih ederim , ancak başka yerlerde zamanlamalardan bahsedildiği için katılabileceğimi düşündüm.
Eğer hızlı yolu istiyorsanız, birleştirebilirsiniz itertools ile 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
Ama birleşiyor izip
ve chain.from_iterable
yine daha hızlı
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
Ayrıca chain(*
ve arasında önemli bir fark vardır
chain.from_iterable(...
.
In [5]: timeit "".join(chain(*izip(l1, l2)))
1 loops, best of 3: 212 ms per loop
Birleştirme ile bir oluşturucu diye bir şey yoktur, birini geçmek her zaman daha yavaş olacaktır, çünkü python içeriği kullanarak bir liste oluşturacaktır, çünkü veri üzerinden iki geçiş yapar, biri gereken boyutu bulmak ve diğeri gerçekten yapmak için bir jeneratör kullanarak mümkün olmayan birleştirme:
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.
*/
Ayrıca farklı uzunluk dizeleriniz varsa ve veri kaybetmek istemiyorsanız izip_longest'i kullanabilirsiniz :
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'
Python 3 için buna denir zip_longest
Ancak python2 için veedrac'ın önerisi açık ara en hızlı olanıdır:
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
list
?? gerekli değil
"".join(list(...))
bana 6.715280318699769 verip sürümüyle gelen timeit "".join(starmap(...))
bana 6.46332361384313 vermek
"".join(list(starmap(add, izip(l1,l2))))
yavaş "".join(starmap(add, izip(l1,l2)))
. Testi makinemde python 2.7.11'de ve python 3.5.1'de hatta www.python.org'un python 3.4.3 ile sanal konsolunda çalıştırıyorum ve hepsi aynı şeyi söylüyor ve birkaç kez çalıştırıyorum ve her zaman aynı
Bunu map
ve kullanarak da yapabilirsiniz operator.add
:
from operator import add
u = 'AAAAA'
l = 'aaaaa'
s = "".join(map(add, u, l))
Çıktı :
'AaAaAaAaAa'
Eşlemin yaptığı şey, her öğeyi ilk yinelenebilirden u
ve ilk öğeleri ikinci yinelemeden alır l
ve ilk argüman olarak sağlanan işlevi uygular add
. O zaman katılmak onlara katılır.
Bu önerilerin çoğu, dizelerin eşit uzunlukta olduğunu varsayar. Belki bu, tüm makul kullanım durumlarını kapsıyor, ancak en azından bana göre, farklı uzunluklardaki dizeleri de yerleştirmek isteyebilirsiniz. Yoksa ağın biraz böyle çalışması gerektiğini düşünen tek kişi ben miyim:
u = "foobar"
l = "baz"
mesh(u,l) = "fboaozbar"
Bunu yapmanın bir yolu şudur:
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:]])
İki for
s kullanmayı seviyorum , değişken isimleri neler olup bittiğine dair bir ipucu / hatırlatıcı verebilir:
"".join(char for pair in zip(u,l) for char in pair)
Burada çift liste-anlama yanıtını dikkate almamak, n dizeyi O (1) çabasıyla ele almak biraz pitonik değil:
"".join(c for cs in itertools.zip_longest(*all_strings) for c in cs)
all_strings
serpiştirmek istediğiniz dizelerin listesi nerede . Sizin durumunuzda all_strings = [u, l]
. Tam kullanım örneği şöyle görünecektir:
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'
Birçok cevap gibi, en hızlı mı? Muhtemelen hayır, ama basit ve esnek. Ayrıca, çok fazla ek karmaşıklık olmadan, bu kabul edilen yanıttan biraz daha hızlıdır (genel olarak, dize eklenmesi python'da biraz yavaştır):
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
Mevcut lider çözümden potansiyel olarak daha hızlı ve daha kısa:
from itertools import chain
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
res = "".join(chain(*zip(u, l)))
Hızlı strateji, mümkün olduğu kadar C seviyesinde yapmaktır. Eşit olmayan dizeler için aynı zip_longest () düzeltmesi ve chain () ile aynı modülden çıkıyor, bu yüzden orada çok fazla puan alamazsın!
Yol boyunca bulduğum diğer çözümler:
res = "".join(u[x] + l[x] for x in range(len(u)))
res = "".join(k + l[i] for i, k in enumerate(u))
1'i kullanabilirsiniteration_utilities.roundrobin
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
from iteration_utilities import roundrobin
''.join(roundrobin(u, l))
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
veya ManyIterables
aynı paketteki sınıf:
from iteration_utilities import ManyIterables
ManyIterables(u, l).roundrobin().as_string()
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
1 Bu yazdım bir üçüncü taraf kitaplığından geçerli: iteration_utilities
.