Quelle est la manière la plus pythonique de mailler deux cordes ensemble?
Par exemple:
Contribution:
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
Production:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
python
string
python-2.7
python-3.x
Brandon Deo
la source
la source
Réponses:
Pour moi, la manière la plus pythonique * est la suivante qui fait à peu près la même chose mais utilise l'
+
opérateur pour concaténer les caractères individuels dans chaque chaîne:C'est également plus rapide que d'utiliser deux
join()
appels:Des approches plus rapides existent, mais elles obscurcissent souvent le code.
Remarque: Si les deux chaînes d'entrée ne sont pas de la même longueur, la plus longue sera tronquée car l'
zip
itération s'arrête à la fin de la chaîne la plus courte. Dans ce cas, au lieu d'zip
un, il faut utiliserzip_longest
(izip_longest
en Python 2) duitertools
module pour s'assurer que les deux chaînes sont complètement épuisées.* Pour reprendre une citation du Zen of Python : la lisibilité compte .
Pythonic = lisibilité pour moi;
i + j
est simplement analysé visuellement plus facilement, du moins pour mes yeux.la source
"".join([i + j for i, j in zip(l1, l2)])
et ce sera certainement le plus rapide"".join(map("".join, zip(l1, l2)))
est encore plus rapide, mais pas nécessairement plus pythonique.Alternative plus rapide
Autrement:
Production:
La vitesse
On dirait que c'est plus rapide:
que la solution la plus rapide à ce jour:
Aussi pour les plus grosses cordes:
Python 3.5.1.
Variation pour les cordes de différentes longueurs
Le plus court détermine la longueur (
zip()
équivalent)Production:
Le plus long détermine la longueur (
itertools.zip_longest(fillvalue='')
équivalent)Production:
la source
Avec
join()
etzip()
.la source
''.join(itertools.chain.from_iterable(zip(u, l)))
zip
s'arrête lorsque la liste plus courte a été entièrement itérée.itertools.zip_longest
peut être utilisé si cela devient un problème.Sur Python 2, le moyen de loin le plus rapide de faire les choses, à ~ 3x la vitesse de découpage de liste pour les petites chaînes et ~ 30x pour les longues, est
Cela ne fonctionnerait pas sur Python 3, cependant. Vous pouvez implémenter quelque chose comme
mais à ce moment-là, vous avez déjà perdu les gains par rapport au découpage de liste pour les petites chaînes (c'est toujours 20x la vitesse pour les longues chaînes) et cela ne fonctionne même pas encore pour les caractères non ASCII.
FWIW, si vous êtes en train de faire cela sur des chaînes massives et ont besoin de chaque cycle, et pour une raison quelconque doivent utiliser des chaînes Python ... voici comment faire:
Un boîtier spécial, le cas courant des types plus petits, aidera également. FWIW, c'est seulement 3 fois la vitesse de découpage de liste pour les longues chaînes et un facteur de 4 à 5 plus lent pour les petites chaînes.
Quoi qu'il en soit, je préfère les
join
solutions, mais comme les horaires ont été mentionnés ailleurs, j'ai pensé que je pourrais aussi bien participer.la source
Si vous voulez le moyen le plus rapide, vous pouvez combiner itertools avec
operator.add
:Mais combiner
izip
etchain.from_iterable
c'est encore plus rapideIl existe également une différence substantielle entre
chain(*
etchain.from_iterable(...
.Il n'y a pas de générateur avec jointure, en transmettre un sera toujours plus lent car python construira d'abord une liste en utilisant le contenu car il effectue deux passes sur les données, un pour déterminer la taille nécessaire et un pour le faire. la jointure qui ne serait pas possible avec un générateur:
join.h :
De plus, si vous avez des chaînes de longueur différente et que vous ne voulez pas perdre de données, vous pouvez utiliser izip_longest :
Pour python 3, il s'appelle
zip_longest
Mais pour python2, la suggestion de veedrac est de loin la plus rapide:
la source
list
?? est inutile"".join(list(...))
give me 6.715280318699769 and timeit the"".join(starmap(...))
give me 6.46332361384313"".join(list(starmap(add, izip(l1,l2))))
est plus lent que"".join(starmap(add, izip(l1,l2)))
. J'exécute le test sur ma machine en python 2.7.11 et en python 3.5.1 même dans la console virtuelle de www.python.org avec python 3.4.3 et tous disent la même chose et je l'exécute plusieurs fois et toujours le sameVous pouvez également le faire en utilisant
map
etoperator.add
:Sortie :
Ce que fait la carte, c'est qu'elle prend chaque élément du premier itérable
u
et les premiers éléments du deuxième itérablel
et applique la fonction fournie comme premier argumentadd
. Ensuite, rejoignez-les simplement.la source
La réponse de Jim est excellente, mais voici mon option préférée, si cela ne vous dérange pas quelques importations:
la source
Un grand nombre de ces suggestions supposent que les chaînes sont de longueur égale. Peut-être que cela couvre tous les cas d'utilisation raisonnables, mais au moins pour moi, il semble que vous souhaitiez peut-être aussi accueillir des chaînes de longueurs différentes. Ou suis-je le seul à penser que le maillage devrait fonctionner un peu comme ceci:
Une façon de procéder serait la suivante:
la source
J'aime utiliser deux
for
s, les noms de variables peuvent donner un indice / rappel de ce qui se passe:la source
Juste pour ajouter une autre approche plus basique:
la source
C'est un peu un-pythonique de ne pas considérer la réponse de compréhension à double liste ici, pour gérer n chaînes avec un effort O (1):
où
all_strings
est une liste des chaînes que vous souhaitez entrelacer. Dans votre casall_strings = [u, l]
,. Un exemple d'utilisation complet ressemblerait à ceci:Comme beaucoup de réponses, le plus rapide? Probablement pas, mais simple et flexible. De plus, sans trop de complexité supplémentaire, c'est légèrement plus rapide que la réponse acceptée (en général, l'ajout de chaînes est un peu lent en python):
la source
Potentiellement plus rapide et plus court que la principale solution actuelle:
La stratégie en termes de vitesse consiste à faire autant que possible au niveau C. Même correctif de zip_longest () pour les chaînes inégales et il sortirait du même module que chain (), donc je ne peux pas me donner trop de points!
Autres solutions que j'ai trouvées en cours de route:
la source
Vous pouvez utiliser 1
iteration_utilities.roundrobin
ou la
ManyIterables
classe du même package:1 Ceci est d'une bibliothèque tierce , je l' ai écrit:
iteration_utilities
.la source
J'utiliserais zip () pour obtenir un moyen lisible et simple:
la source