15

He encontrado este problema varias veces y parece que no puede encontrar una solución simple. Decir que tengo una cadenaconvertir cadena a dict utilizando lista de comprensión en python

string = "a=0 b=1 c=3" 

Quiero convertir esto en un diccionario con a, b y c es la clave y 0, 1, y 3 siendo sus respectivos valores (convertido a int). Obviamente, yo puedo hacer esto:

list = string.split() 
    dic = {} 
    for entry in list: 
     key, val = entry.split('=') 
     dic[key] = int(val) 

pero no me gusta mucho ese bucle, Parece tan simple que usted debería ser capaz de convertirlo en una especie de expresión de lista por comprensión. Y eso funciona para casos ligeramente más simples donde el val puede ser una cadena.

dic = dict([entry.split('=') for entry in list]) 

Sin embargo, necesito convertir val a un int sobre la marcha y hacer algo como esto es sintácticamente incorrecto.

dic = dict([[entry[0], int(entry[1])] for entry.split('=') in list]) 

Así que mi pregunta es: ¿hay alguna manera de eliminar el bucle for utilizando la lista de comprensión? Si no, ¿hay algún método de python integrado que lo haga por mí?

+0

Nota: No utilice funciones integradas como nombres de variables ('string',' list', etc.) –

Respuesta

29

¿Te refieres a esto?

>>> dict((n,int(v)) for n,v in (a.split('=') for a in string.split())) 
{'a': 0, 'c': 3, 'b': 1} 
+4

Mientras eso está bien, creo que prefiero la versión en la pregunta original de un largo plazo punto de vista de mantenimiento del código. El código en la pregunta original es claro y obvio, lo anterior requiere varias decenas de segundos para grok. –

+1

@Bryan Oakley: Estoy de acuerdo. La pregunta ("¿hay alguna manera de eliminar el bucle for utilizando la lista de comprensión?") Tiene una respuesta. Sin embargo, la respuesta puede no ser lo que ** realmente ** quería. –

+1

Sí, eso es lo que estaba buscando. Gracias. @Bryan: Estoy empezando a pensar que tal vez mantener ese ciclo sea una buena idea. Sin embargo, al menos ahora sé cómo hacer esto en una línea. – Pavel

1
from cgi import parse_qsl 
text = "a=0 b=1 c=3" 
dic = dict((k, int(v)) for k, v in parse_qsl(text.replace(' ', '&'))) 
print dic 

impresiones

{'a': 0, 'c': 3, 'b': 1} 
+0

Agradable ......... 15. –

-3

me gusta la solución de S. Lott, pero se le ocurrió otra posibilidad.
Como usted ya tiene una cadena que se asemeja de alguna manera la forma en que iba a escribir de eso, sólo puede adaptarlo a la sintaxis de Python y luego eval() que :)

import re 
string = "a=0 b=1 c=3" 
string2 = "{"+ re.sub('(|^)(?P<id>\w+)=(?P<val>\d+)', ' "\g<id>":\g<val>,', string) +"}" 
dict = eval(string2) 
print type(string), type(string2), type(dict) 
print string, string2, dict 

La expresión regular aquí es bastante cruda y ganado' t atrapar todos los posibles identificadores de Python, pero quería hacerlo simple por simplicidad. Por supuesto, si tiene control sobre cómo se genera la cadena de entrada, solo genere de acuerdo con la sintaxis de Python y desactívela. ¡PERO, por supuesto, debe realizar comprobaciones de cordura adicionales para asegurarse de que no se haya insertado ningún código allí!

+2

querías mantener esto simple? no ser malo o molestar a nadie, pero ¿dónde es esto simple? – Nope

3

¿Qué tal un trazador de líneas sin lista de comprensión?

foo="a=0 b=1 c=3" 
ans=eval('dict(%s)'%foo.replace(' ',','))) 
print ans 
{'a': 0, 'c': 3, 'b': 1} 
+0

sé cómo eval funciona pero tengo problemas para entender esto – Ajay

+1

El foo.replace() convierte "a = 0 b = 1 c = 3" en "a = 0, b = 1, c = 3". El formato de cadena crea una nueva cadena "dict (a = 0, b = 1, c = 3)". Evaluar esa cadena produce el dict deseado. –

+0

Me tomó un tiempo entender ... – Ajay

3

pruebe el siguiente:

dict([x.split('=') for x in s.split()]) 
+1

OP quería que el segundo elemento de la lista se convirtiera en un número entero. – hughdbrown

2

a veces me gusta este enfoque, sobre todo cuando la lógica para hacer las claves y valores es más complicado:

s = "a=0 b=1 c=3" 

def get_key_val(x): 
    a,b = x.split('=') 
    return a,int(b) 

ans = dict(map(get_key_val,s.split())) 
0

Me gustaría hacer esto:

def kv(e): return (e[0], int(e[1])) 
d = dict([kv(e.split("=")) for e in string.split(" ")]) 
2

Hoy en día s hould probablemente utilizar un diccionario por comprensión, introducido en 2.7:

mydict = {key: int(value) for key, value in (a.split('=') for a in mystring.split())} 

El diccionario por comprensión es más rápido y más brillante (y, en mi opinión, más legible).

from timeit import timeit 

setup = """mystring = "a=0 b=1 c=3\"""" 
code1 = """mydict = dict((n,int(v)) for n,v in (a.split('=') for a in mystring.split()))""" # S.Lott's code 
code2 = """mydict = {key: int(value) for key, value in (a.split('=') for a in mystring.split())}""" 

print timeit(code1, setup=setup, number=10000) # 0.115524053574 
print timeit(code2, setup=setup, number=10000) # 0.105328798294 
Cuestiones relacionadas