convert string to dict using list comprehension
Asked Answered
H

8

15

I have came across this problem a few times and can't seem to figure out a simple solution. Say I have a string

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

I want to convert that into a dictionary with a, b and c being the key and 0, 1, and 3 being their respective values (converted to int). Obviously I can do this:

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

But I don't really like that for loop, It seems so simple that you should be able to convert it to some sort of list comprehension expression. And that works for slightly simpler cases where the val can be a string.

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

However, I need to convert val to an int on the fly and doing something like this is syntactically incorrect.

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

So my question is: is there a way to eliminate the for loop using list comprehension? If not, is there some built in python method that will do that for me?

Helms answered 7/8, 2009 at 19:0 Comment(1)
Note: Don't use built in functions as variable names (string, list, etc.)Amabil
G
29

Do you mean this?

>>> dict( (n,int(v)) for n,v in (a.split('=') for a in string.split() ) )
{'a': 0, 'c': 3, 'b': 1}
Grandmotherly answered 7/8, 2009 at 19:7 Comment(2)
While that's cool, I think I prefer the version in the original question from a long-term code maintenance point of view. The code in the original question is clear and obvious, the above requires multiple tens of seconds to grok.Diorio
@Bryan Oakley: I agree. The question ("is there a way to eliminate the for loop using list comprehension") has an answer. However, the answer may not be what they really wanted.Grandmotherly
C
3

How about a one-liner without list comprehension?

 foo="a=0 b=1 c=3"
 ans=eval( 'dict(%s)'%foo.replace(' ',',')) )
 print ans
{'a': 0, 'c': 3, 'b': 1}
Casie answered 8/8, 2009 at 1:50 Comment(1)
The foo.replace() turns "a=0 b=1 c=3" into "a=0,b=1,c=3". The string formatting creates a new string "dict(a=0,b=1,c=3)". Eval'ing that string produces the desired dict.Casie
B
3

Try the next:

dict([x.split('=') for x in s.split()])
Brewington answered 8/8, 2009 at 14:17 Comment(1)
OP wanted the second element of the list cast to an integer.Amylopectin
D
2

I sometimes like this approach, especially when the logic for making keys and values is more complicated:

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()))
Deonnadeonne answered 8/8, 2009 at 14:50 Comment(0)
O
2

Nowadays you should probably use a dictionary comprehension, introduced in 2.7:

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

The dictionary comprehension is faster and shinier (and, in my opinion, more readable).

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
Oculus answered 20/11, 2014 at 7:13 Comment(0)
R
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

prints

{'a': 0, 'c': 3, 'b': 1}
Ruckus answered 7/8, 2009 at 19:32 Comment(0)
C
0

I would do this:

def kv(e): return (e[0], int(e[1]))
d = dict([kv(e.split("=")) for e in string.split(" ")])
Colubrid answered 12/6, 2010 at 22:37 Comment(0)
S
-3

I like S.Lott's solution, but I came up with another possibility.
Since you already have a string resembling somehow the way you'd write that, you can just adapt it to python syntax and then 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

The regex here is pretty raw and won't catch all the possible python identifiers, but I wanted to keep it simple for simplicity's sake. Of course if you have control over how the input string is generated, just generate it according to python syntax and eval it away. BUT of course you should perform additional sanity checks to make sure that no code is injected there!

Scrimshaw answered 7/8, 2009 at 21:16 Comment(1)
you wanted to keep this simple? not to be mean or pick on anyone but where is this simple?Gyimah

© 2022 - 2024 — McMap. All rights reserved.