Qual é a maneira mais pythônica de unir duas cordas?
Por exemplo:
Entrada:
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
Resultado:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
python
string
python-2.7
python-3.x
Brandon Deo
fonte
fonte
Respostas:
Para mim, a maneira mais pythônica * é a seguinte, que faz praticamente a mesma coisa, mas usa o
+
operador para concatenar os caracteres individuais em cada string:Também é mais rápido do que usar duas
join()
chamadas:Existem abordagens mais rápidas, mas muitas vezes ofuscam o código.
Nota: Se as duas strings de entrada não tiverem o mesmo comprimento, a mais longa será truncada, pois
zip
para de iterar no final da string mais curta. Neste caso, em vez dezip
um, deve-se usarzip_longest
(izip_longest
no Python 2) doitertools
módulo para garantir que ambas as strings estejam totalmente esgotadas.* Para fazer uma citação do Zen do Python : Contagens de legibilidade .
Pythônico = legibilidade para mim;
i + j
é apenas analisado visualmente com mais facilidade, pelo menos para os meus olhos.fonte
"".join([i + j for i, j in zip(l1, l2)])
e será definitivamente o mais rápido"".join(map("".join, zip(l1, l2)))
é ainda mais rápido, embora não necessariamente mais python.Alternativa mais rápida
Outra maneira:
Resultado:
Rapidez
Parece que é mais rápido:
do que a solução mais rápida até agora:
Também para strings maiores:
Python 3.5.1.
Variação para cordas com diferentes comprimentos
O mais curto determina o comprimento (
zip()
equivalente)Resultado:
O mais longo determina o comprimento (
itertools.zip_longest(fillvalue='')
equivalente)Resultado:
fonte
Com
join()
ezip()
.fonte
''.join(itertools.chain.from_iterable(zip(u, l)))
zip
para quando a lista menor tiver sido totalmente iterada.itertools.zip_longest
pode ser usado se se tornar um problema.No Python 2, de longe a maneira mais rápida de fazer as coisas, em ~ 3x a velocidade do fatiamento de lista para strings pequenas e ~ 30x para strings longas, é
Isso não funcionaria no Python 3, no entanto. Você poderia implementar algo como
mas, a essa altura, você já perdeu os ganhos com o fatiamento de lista para strings pequenas (ainda é 20x a velocidade para strings longas) e isso nem funciona para caracteres não ASCII ainda.
FWIW, se você está fazendo isso em strings massivas e precisa de cada ciclo e , por algum motivo, precisa usar strings Python ... veja como fazer:
A embalagem especial, o caso comum de tipos menores, também ajudará. FWIW, esta é apenas 3x a velocidade de corte de lista para cordas longas e um fator de 4 a 5 mais lento para cordas pequenas.
De qualquer forma, prefiro as
join
soluções, mas como os horários foram mencionados em outro lugar, achei melhor participar.fonte
Se você quiser a maneira mais rápida, pode combinar itertools com
operator.add
:Mas combinar
izip
echain.from_iterable
é mais rápido novamenteTambém há uma diferença substancial entre
chain(*
echain.from_iterable(...
.Não existe gerador com junção, a passagem de um sempre será mais lenta, pois o python primeiro construirá uma lista usando o conteúdo porque faz duas passagens sobre os dados, uma para descobrir o tamanho necessário e outra para realmente fazer a junção que não seria possível usando um gerador:
join.h :
Além disso, se você tiver strings de comprimento diferente e não quiser perder dados, pode usar izip_longest :
Para python 3 é chamado
zip_longest
Mas para python2, a sugestão de veedrac é de longe a mais rápida:
fonte
list
?? é desnecessário"".join(list(...))
para me dar 6,715280318699769 e timeit"".join(starmap(...))
para me dar 6,46332361384313"".join(list(starmap(add, izip(l1,l2))))
é mais lento do que"".join(starmap(add, izip(l1,l2)))
. Eu executo o teste em minha máquina em python 2.7.11 e em python 3.5.1 até mesmo no console virtual de www.python.org com python 3.4.3 e todos dizem o mesmo e eu o executo algumas vezes e sempre o mesmoVocê também pode fazer isso usando
map
eoperator.add
:Produto :
O que o mapa faz é pegar cada elemento do primeiro iterável
u
e os primeiros elementos do segundo iterávell
e aplicar a função fornecida como o primeiro argumentoadd
. Em seguida, junte-se a eles.fonte
A resposta de Jim é ótima, mas aqui está minha opção favorita, se você não se importar com algumas importações:
fonte
Muitas dessas sugestões assumem que as strings têm o mesmo comprimento. Talvez isso cubra todos os casos de uso razoáveis, mas pelo menos para mim parece que você pode querer acomodar strings de comprimentos diferentes também. Ou eu sou o único pensando que a malha deveria funcionar um pouco assim:
Uma maneira de fazer isso seria a seguinte:
fonte
Eu gosto de usar dois
for
s, os nomes das variáveis podem dar uma dica / lembrete do que está acontecendo:fonte
Apenas para adicionar outra abordagem mais básica:
fonte
Parece um pouco não-pythônico não considerar a resposta de compreensão de lista dupla aqui, para lidar com n strings com esforço O (1):
onde
all_strings
está uma lista das strings que você deseja intercalar. No seu casoall_strings = [u, l]
,. Um exemplo de uso completo ficaria assim:Como muitas respostas, mais rápido? Provavelmente não, mas simples e flexível. Além disso, sem adicionar muita complexidade, isso é um pouco mais rápido do que a resposta aceita (em geral, a adição de string é um pouco lenta em python):
fonte
Potencialmente mais rápido e mais curto do que a solução líder atual:
A estratégia em termos de velocidade é fazer o máximo possível no nível C. A mesma correção zip_longest () para strings desiguais e ela sairia do mesmo módulo que chain (), portanto, não pode me dar muitos pontos aí!
Outras soluções que encontrei ao longo do caminho:
fonte
Você poderia usar 1
iteration_utilities.roundrobin
ou a
ManyIterables
classe do mesmo pacote:1 Esta é a partir de uma biblioteca de terceiros que tenho escrito:
iteration_utilities
.fonte
Eu usaria zip () para obter uma maneira fácil e legível:
fonte