Quel est le moyen plus Pythonique à mailler deux cordes ensemble ?
Par exemple :
Entrée :
Sortie :
Quel est le moyen plus Pythonique à mailler deux cordes ensemble ?
Par exemple :
Entrée :
Sortie :
Pour moi, le plus pythonic* est la suivante qui assez bien fait la même chose , mais utilise l' +
de l'opérateur de concaténation de caractères individuels dans chaque chaîne:
res = "".join(i + j for i, j in zip(u, l))
print(res)
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
Il est également plus rapide que l'utilisation de deux join()
appels:
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
Plus vite approches existent, mais ils sont souvent obscurcir le code.
Remarque: Si les deux chaînes d'entrée sont pas de la même longueur, alors le plus long sera tronquée zip
l'itération s'arrête à la fin de la chaîne plus courte. Dans ce cas, au lieu de zip
il faut utiliser zip_longest
(izip_longest
en Python 2) de l' itertools
module pour vous assurer que les deux chaînes sont entièrement épuisé.
*Pour prendre une citation de la Zen de Python: la Lisibilité compte.
Pythonic = lisibilité pour moi; i + j
est juste visuellement analysé plus facilement, au moins pour mes yeux.
D'une autre manière:
res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
print(''.join(res))
Sortie:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
Regarde comme il est plus rapide:
%%timeit
res = [''] * len(u) * 2
res[::2] = u
res[1::2] = l
''.join(res)
100000 loops, best of 3: 4.75 µs per loop
que la solution la plus rapide à ce jour:
%timeit "".join(list(chain.from_iterable(zip(u, l))))
100000 loops, best of 3: 6.52 µs per loop
Aussi pour les plus grandes chaînes:
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()
équivalent)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))
Sortie:
AaBbCcDdEeFfGgHhIiJjKkLl
itertools.zip_longest(fillvalue='')
équivalent)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))
Sortie:
AaBbCcDdEeFfGgHhIiJjKkLlMNOPQRSTUVWXYZ
Sur Python 2, par la mesure la plus rapide façon de faire les choses, à ~3x la vitesse de la liste de découpage pour les petites chaînes et ~30x pour longtemps, est
res = bytearray(len(u) * 2)
res[::2] = u
res[1::2] = l
str(res)
Ceci ne fonctionnerait pas sur Python 3, mais. Vous pourriez mettre en place quelque chose comme
res = bytearray(len(u) * 2)
res[::2] = u.encode("ascii")
res[1::2] = l.encode("ascii")
res.decode("ascii")
mais d'ici là, vous avez déjà perdu les gains sur la liste de découpage pour les petites chaînes (c'est toujours 20x la vitesse pendant de longues chaînes de caractères) et cela ne fonctionne pas même pour les caractères non-ASCII encore.
FWIW, si vous êtes de faire cela massive des chaînes et besoin de chaque cycle, et pour une raison quelconque, ont pour utiliser Python chaînes... voici comment faire:
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")
Spécial-boîtier le cas le plus courant de plus petits types aidera aussi. FWIW, ce n'est 3x la vitesse de la liste de découpage pour les longues chaînes de caractères et un facteur de 4 à 5 plus lent pour les petites chaînes.
De toute façon, je préfère l' join
solutions, mais depuis timings ont été mentionnées ailleurs j'ai pensé que je pourrais aussi bien se joindre à eux.
Si vous voulez le moyen le plus rapide, vous pouvez combiner itertools avec 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
Mais en combinant izip
et chain.from_iterable
est plus rapide encore
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
Il y a également une différence importante entre l'
chain(*
et chain.from_iterable(...
.
In [5]: timeit "".join(chain(*izip(l1, l2)))
1 loops, best of 3: 212 ms per loop
Il n'y a pas une telle chose comme un générateur de rejoindre, en passant de l'un est toujours plus lente que python va tout d'abord créer une liste en utilisant le contenu, car il n'deux passes sur les données, une pour déterminer la taille nécessaire et l'un de vraiment faire la jointure qui ne serait pas possible à l'aide d'un générateur:
/* 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.
*/
Aussi, si vous avez différentes chaînes de longueur et vous ne voulez pas perdre vos données, vous pouvez utiliser 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'
Pour python 3, il est appelé zip_longest
Mais pour python2, veedrac la suggestion est de loin la plus rapide:
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
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.