15

Je suis tombé sur ce problème à quelques reprises et n'arrive pas à trouver une solution simple. que j'ai une chaîneconvertir la chaîne à dict en utilisant la compréhension de la liste en python

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

Je souhaite convertir en un dictionnaire avec a, b et c étant la clé et 0, 1 et 3 étant leurs valeurs respectives (converti en int). Il est évident que je peux faire ceci:

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

Mais je ne sais vraiment pas comme ça pour la boucle, il semble si simple que vous devriez être en mesure de le convertir en une sorte d'expression de la compréhension de la liste. Et cela fonctionne pour les cas légèrement plus simples où le val peut être une chaîne. Cependant, j'ai besoin de convertir val en un int à la volée et faire quelque chose comme ceci est syntaxiquement incorrect. Donc, ma question est la suivante: y a-t-il un moyen d'éliminer la boucle for en utilisant la compréhension de la liste? Sinon, y a-t-il une méthode python intégrée qui fera ça pour moi?

+0

Note: Ne pas utiliser des fonctions intégrées comme noms de variables ('string',' list', etc.) –

Répondre

29

Voulez-vous dire cela?

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

Bien que ce soit cool, je pense que je préfère la version originale dans la question d'un long terme point de vue de maintenance de code. Le code dans la question d'origine est clair et évident, ce qui précède nécessite plusieurs dizaines de secondes pour grok. –

+1

@Brian Oakley: Je suis d'accord. La question ("existe-t-il un moyen d'éliminer la boucle for en utilisant la compréhension de la liste") a une réponse. Cependant, la réponse n'est peut-être pas ce qu'ils voulaient ** vraiment **. –

+1

Oui c'est ce que je cherchais. Je vous remercie. @Brian: Je commence à penser que peut-être garder cette boucle est probablement une bonne idée. Néanmoins, au moins maintenant je sais comment faire cela en une ligne. – 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 

impressions

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

Nice ......... 15. –

-3

J'aime la solution de S. Lott, mais je suis venu avec une autre possibilité.
Puisque vous avez déjà une chaîne qui ressemble en quelque sorte la façon dont vous écririez que, vous pouvez simplement l'adapter à la syntaxe python puis eval() :) il

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 

Le regex ici est assez cru et gagné » J'attrapais tous les identifiants python possibles, mais je voulais le garder simple pour la simplicité. Bien sûr, si vous avez le contrôle sur la façon dont la chaîne d'entrée est générée, générez-la simplement en fonction de la syntaxe python et évaluez-la. MAIS bien sûr, vous devriez effectuer des vérifications supplémentaires pour s'assurer qu'aucun code n'est injecté là!

+2

vous vouliez garder cela aussi simple? ne pas être méchant ou choisir quelqu'un mais où est-ce simple? – Nope

3

Que diriez-vous d'un one-liner sans compréhension de liste?

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

Je sais comment eval fonctionne mais j'ai du mal à comprendre cela – Ajay

+1

Le foo.replace() transforme "a = 0 b = 1 c = 3" en "a = 0, b = 1, c = 3". Le formatage de chaîne crée une nouvelle chaîne "dict (a = 0, b = 1, c = 3)". L'évaluation de cette chaîne produit la dictée désirée. –

+0

Il m'a fallu un certain temps pour comprendre .. – Ajay

3

Essayez la prochaine:

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

OP voulait le deuxième élément de la liste cast à un nombre entier. – hughdbrown

2

Je parfois comme cette approche, surtout quand la logique pour faire des clés et des valeurs est plus compliquée:

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

je ferais ceci:

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

De nos jours s Hould probablement utiliser un dictionnaire de compréhension, introduit dans 2.7:

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

La compréhension du dictionnaire est plus rapide et plus brillante (et, à mon avis, plus lisible).

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