Pergunta

Eu me deparei com esse problema algumas vezes e não consigo descobrir uma solução simples. Diga que tenho uma corda

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

Quero convertê -lo em um dicionário com A, B e C sendo a chave e 0, 1 e 3 sendo seus respectivos valores (convertidos em int). Obviamente eu posso fazer isso:

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

Mas eu realmente não gosto disso para o loop, parece tão simples que você pode convertê -lo em algum tipo de expressão de compreensão da lista. E isso funciona para casos um pouco mais simples em que o val pode ser uma string.

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

No entanto, preciso converter Val em um INT em tempo real e fazer algo assim é sintaticamente incorreto.

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

Portanto, minha pergunta é: existe uma maneira de eliminar o loop for usando a compreensão da lista? Caso contrário, há algum método construído no Python que fará isso por mim?

Foi útil?

Solução

Você quer dizer isso?

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

Outras dicas

Que tal uma liner sem compreensão da lista?

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

Experimente o próximo:

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

Às vezes gosto dessa abordagem, especialmente quando a lógica para fazer chaves e valores é mais complicada:

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()))

Atualmente, você provavelmente deve usar uma compreensão do dicionário, introduzida em 2.7:

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

A compreensão do dicionário é mais rápida e mais brilhante (e, na minha opinião, mais legível).

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
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

impressões

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

Eu faria isso:

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

Gosto da solução de S.Lott, mas criei outra possibilidade.
Como você já tem uma string parecida com a maneira como escreveria isso, você pode simplesmente adaptá -la à sintaxe python e depois avaliar () :)

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

O Regex aqui é bastante cru e não captura todos os possíveis identificadores de Python, mas eu queria simplificar por uma questão de simplicidade. Obviamente, se você tiver controle sobre como a sequência de entrada é gerada, basta gerá -la de acordo com a sintaxe do Python e avaliar -a. Mas é claro que você deve executar verificações adicionais de sanidade para garantir que nenhum código seja injetado lá!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top