15

Ho riscontrato questo problema alcune volte e non riesco a trovare una soluzione semplice. Dire che ho una stringaconvertire la stringa in dettare utilizzando la comprensione degli elenchi in python

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

voglio convertire in un dizionario con a, b e c è la chiave e 0, 1, e 3 essendo i rispettivi valori (convertito in int). Ovviamente posso fare questo:

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

Ma io in realtà non così per ciclo, Sembra così semplice che si dovrebbe essere in grado di convertirlo in una sorta di espressione di lista. E questo funziona per i casi leggermente più semplici in cui lo val può essere una stringa.

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

Tuttavia, ho bisogno di convertire val ad un int al volo e fare qualcosa di simile è sintatticamente corretto.

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

Quindi la mia domanda è: esiste un modo per eliminare il ciclo for usando di lista? In caso contrario, c'è qualche costruito in Python che lo farà per me?

+0

Nota: Non usare costruito nelle funzioni come nomi di variabili ('STRING',' list', etc.) –

risposta

29

Intendi questo?

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

Mentre questo è fresco, credo di preferire la versione nella domanda originale da una a lungo termine punto di vista della manutenzione del codice. Il codice nella domanda originale è chiaro e ovvio, quanto sopra richiede più decine di secondi per ingannare. –

+1

@Bryan Oakley: sono d'accordo. La domanda ("esiste un modo per eliminare il ciclo for usando la comprensione delle liste") ha una risposta. Tuttavia, la risposta potrebbe non essere quella che loro ** volevano veramente **. –

+1

Sì, questo è quello che stavo cercando. Grazie. @Bryan: Sto iniziando a pensare che forse mantenere questo ciclo è probabilmente una buona idea. Tuttavia, almeno ora so come farlo in una riga. – 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 

stampe

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

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

-3

Mi piace la soluzione di S. Lott, ma mi si avvicinò con un'altra possibilità.
Dal momento che si dispone già di una stringa che assomiglia in qualche modo il modo in cui devi scrivere che, si può solo adattarla alle sintassi Python e quindi eval() it :)

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 

L'espressione regolare qui è abbastanza grezza e ha vinto' t prendere tutti i possibili identificatori di python, ma volevo mantenerlo semplice per semplicità. Ovviamente se si ha il controllo su come viene generata la stringa di input, è sufficiente generarla in base alla sintassi python e evitarla. MA naturalmente si dovrebbero eseguire ulteriori controlli di integrità per assicurarsi che non vi sia iniettato alcun codice!

+2

si voleva mantenere questo semplice? non essere cattivo o scegliere nessuno, ma dov'è questo semplice? – Nope

3

Che ne dici di un one-liner senza la comprensione delle liste?

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

so come funziona ancora, ma ho difficoltà a capire questo – Ajay

+1

Il foo.replace() gira "a = 0 b = 1 c = 3" in "a = 0, b = 1, c = 3". La formattazione della stringa crea una nuova stringa "dict (a = 0, b = 1, c = 3)". Evaling quella stringa produce il dettato desiderato. –

+0

Mi ci è voluto un po 'per capire .. – Ajay

3

provare il prossimo:

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

OP voleva che il secondo elemento della lista fosse lanciato su un numero intero. – hughdbrown

2

volte mi piace questo approccio, soprattutto quando la logica per la realizzazione chiavi e valori è più complicata:

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

farei questo:

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

Al giorno d'oggi s hould probabilmente utilizzare una comprensione dizionario, introdotto in 2.7:

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

La comprensione dizionario è più veloce e più lucidi (e, a mio parere, più leggibile).

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