2010-01-25 16 views
28

Dada esta inofensiva pequeña lista:manera más Pythonic para concatenar cadenas

>>> lst = ['o','s','s','a','m','a'] 

Mi objetivo es concatenar pythonically los pequeños demonios utilizando una de las siguientes maneras:

A. ol llano' función de cadena de hacer el trabajo, cortas, no hay importaciones

>>> ''.join(lst) 
'ossama' 

B. lambda, lambda, lambda

>>> reduce(lambda x, y: x + y, lst) 
'ossama' 

C. globalización (no hacer nada, importar todo)

>>> import functools, operator 
>>> functools.reduce(operator.add, lst) 
'ossama' 

Para sugerir otras formas Pythonic para lograr esta tarea magnánima.

Clasifique las soluciones de rango (nivel pythonic) y proporcione explicaciones concisas.

En este caso, ¿la solución más pitónica es la mejor solución de codificación?

Respuesta

29

Eche un vistazo a essay de Guido en la optimización de Python, cubre la conversión de listas de números a cadenas. A menos que tenga una buena razón de lo contrario, use el ejemplo join.

55
''.join(lst) 

la única manera Pythonic:

  • claro (que lo que todos los grandes hacen y lo que esperan ver),
  • simples (no hay importaciones adicionales necesarios, estable en todas las versiones) ,
  • rápido (escrito en C) y
  • conciso (en un elemento de unión de cadena vacía de iterable!).
+2

Mientras que las soluciones basadas en reducir son elegantes y el programador funcional en mí las aprecia, debo aceptar que join() es de hecho la única solución pitonica. – liwp

+1

SilentGhost tiene razón. Las cadenas tienen un método de combinación que acepta iterables, por lo que usar cualquier otra cosa no es pitónico. – stefanw

+0

Entonces, gente, pls, verifique el tipo nativo de "bytearray", responda a continuación). Sin embargo, unirse es ubinable hasta Python 2.5. – jsbueno

5

Aquí es la forma menos Pythonic:

out = "" 
for x in range(len(lst)): 
    for y in range(len(lst)): 
    if x + y == len(lst)-1: 
     out = lst[y] + out 
+3

Apuesto a que hay formas de reducir la pitonicidad en eso. ;) –

+0

No es realmente lo que pidió, pero veo tu punto ..... :-) –

5

Yo mismo uso el camino "unir", pero a partir de Python 2.6 no es un tipo de base que se utiliza poco: bytearray.

Bytearrays puede ser increíblemente útil - para textos que contienen cuerdas, ya que lo mejor es tenerlos en unicode, la manera de "unirse" es el camino a seguir, pero si se trata de datos binarios, bytearrays puede ser a la vez más Pythonic y más eficiente:

>>> lst = ['o','s','s','a','m','a'] 
>>> a = bytearray(lst) 
>>> a 
bytearray(b'ossama') 
>>> print a 
ossama 

está construido en un tipo de datos: ninguna importación necesaria - sólo tiene que utilizar a continuación - y se puede utilizar un isntead bytearray de una lista para comenzar con - por lo que debe ser más efficinet que el "join", ya que no hay copia de datos para obtener la representación de cadena para un bytearray.

+0

hmm ... simplemente verificado: el constructor "bytearray" puede obtener incluso una cadena Unicode y un argumento de "codificación" para que pueda tratar con unicode también. p.ej. : a = bytearray (u "déja-vu", encoding = "utf8") – jsbueno

+1

excepto que bytearrays no son ni pitónicos ni eficientes. Están destinados a un propósito completamente diferente, y su comportamiento en py2.6 no es el mismo que en py3k. – SilentGhost

+0

@SilentGhost: Gracias por sus comentarios. ¿Dónde puedo obtener más información al respecto? E incluso si no son tan eficientes como podrían parecer primero, dudo que "unirse" pueda ser más rápido simplemente debido a la creación de un nuevo objeto riguroso por parte para concatenar. (Tengo la intención de hacer una evaluación comparativa más tarde hoy) – jsbueno

3

Gran respuesta de SilenGhost PERO, sólo unas pocas palabras acerca de la presentada reduce "alternativo"

A menos que tenga una muy MUY buena razón para concatenar cadenas utilizando + o operator.add (la más frecuente , que tiene pocas, cantidad fija de cadenas), debe usar siempre join.

Simplemente porque cada + genera una nueva cadena que es la concatenación de dos cadenas, a menos que la unión solo genere una cadena final. Por lo tanto, imagina que tienes 3 cadenas:

A + B + C 
--> 
D = A + B 
final = D + C 

Ok, no, no parece mucho, pero tienes que reservar memoria para D. Además, debido uso de cadenas pitón, generando una nueva, intermedia , cuerda, de alguna manera es caro ...

Ahora, con 5 cuerdas

A + B + C + D + E 
--> 
F = A + B 
G = F + C 
H = G + D 
final = H + E 

Suponiendo que el mejor de los casos (si lo hacemos (A + B) + (C + D) + E, vamos fin de tener tres cadenas intermedias al mismo tiempo en la memoria), eso genera 3 cadenas intermedias ... Tienes que generar un nuevo objeto python, reserv espacio de memoria ve, liberar la memoria un par de veces ... También la sobrecarga de llamar a una función de Python (que no es pequeño)

Ahora piense en ello con 200 cadenas. Terminaremos con un ridículo gran número de cadenas intermedias, cada una de ellas consumiendo combinando bastante tiempo en ser una lista completa sobre python, y llamando a un montón de funciones operator.add, cada una con su sobrecarga ... Incluso si usa reduce funciones, no ayudará. Es un problema que tiene que ser manejado con un enfoque diferente: join, que solo genera ONE cadena completa de python, la última y llama a UNA función python.

(Por supuesto, join, u otra función similar, especializada para arrays)

16

Por supuesto que es join. ¿Cómo puedo saber? Hagámoslo de una manera realmente estúpida:
Si el problema fue solo agregar 2 cadenas, lo más probable es que uses str1 + str2. ¿Qué se necesita para llevar eso al siguiente nivel? Instintivamente, para la mayoría (creo), será usar sum. Veamos cómo va eso:

In [1]: example = ['a', 'b', 'c'] 
In [2]: sum(example, '') 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython console> in <module>() 
TypeError: sum() can't sum strings [use ''.join(seq) instead] 

¡Guau! ¡Python simplemente me dijo qué usar! :)

Cuestiones relacionadas