4

I need to convert a comma separated string with key value pairs separated by colon into a dictionary where value is expected to be a float. I'm able to do this to get a dict:

>>> s = 'us:0.9,can:1.2,mex:0.45'
>>> dict(x.split(':') for x in s.split(','))

which results in:

{'us': '0.9', 'can': '1.2', 'mex': '0.45'}

but not sure how to force the value to be not a string ie, I'm expecting this:

{'us': 0.9, 'can': 1.2, 'mex': 0.45}

How to force the values to be floats?

Thanks!

Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
user2727704
  • 625
  • 1
  • 10
  • 21
  • This is how you convert it to float: `float('0.9')`. – Muzol Sep 06 '18 at 00:50
  • Does this answer your question? [Splitting a semicolon-separated string to a dictionary, in Python](https://stackoverflow.com/questions/186857/splitting-a-semicolon-separated-string-to-a-dictionary-in-python) – Tomerikoo Feb 08 '21 at 10:59

5 Answers5

16

How about:

{k: float(v) for k, v in [i.split(':') for i in s.split(',')]}
g.d.d.c
  • 46,865
  • 9
  • 101
  • 111
1

Maybe it can be confusing but you can try this :

s = 'us:0.9,can:1.2,mex:0.45'

dict((a, float(b)) for a,b in [x.split(':') for x in s.split(',')])

The output :

{'us': 0.9, 'can': 1.2, 'mex': 0.45}
fredkiss
  • 21
  • 2
  • 4
0

You can define a function for this:

s = 'us:0.9,can:1.2,mex:0.45'

def key_val_split(L):
    key, val = L.split(':')
    return key, float(val)

res = dict(key_val_split(x) for x in s.split(','))

{'us': 0.9, 'can': 1.2, 'mex': 0.45}
jpp
  • 159,742
  • 34
  • 281
  • 339
  • Works, but is probably overkill - this can be done inline with a comprehension. – g.d.d.c Sep 06 '18 at 00:53
  • 1
    One line isn't necessarily better (but probably is more efficient here). In my opinion, though, the verbose function is more readable. – jpp Sep 06 '18 at 00:55
  • 1
    Debatable. In a short code snippet like this, sure. If your `key_val_split` function is defined somewhere far away from where it's used and I have to go find it while I'm debugging an issue, then definitely not. The comprehension is all in one place, and always displayed together. – g.d.d.c Sep 06 '18 at 01:03
  • 1
    There are *plenty* of examples where "displayed together" is an awful idea. But we can agree to disagree. Certainly I find this more readable. But I'm more of a functional guy. – jpp Sep 06 '18 at 01:05
0

Try this:

s = 'us:0.9,can:1.2,mex:0.45'
t = {k:float(v) for k, v in dict(x.split(':') for x in s.split(',')).items()}
print(t)

Output is:

{'us': 0.9, 'can': 1.2, 'mex': 0.45}
shahbazkhan
  • 156
  • 2
  • 8
  • 2
    While this does work, it's overworked. It's creating a dictionary to iterate over to parse the floats - there's really no need for that if you just consume the inner list comprehension. This is twice as many iterations as is necessary. – g.d.d.c Sep 06 '18 at 00:55
  • Hmm, I'm a bit confused. Isn't your answer creating a list of lists, and iterating over to parse the floats. Where this is creating a dictionary, where I iterate over to parse the floats? I'm confused on how this has twice as many iterations as necessary. Could you explain for my understanding? (although I agree with your solution) – shahbazkhan Sep 06 '18 at 01:11
  • 1
    Sure. The crux of it is that you create a list of lists with `x.split(':') for x in s.split(',')` (more specifically, a generator, but that distinction isn't hugely relevant to this discussion), and then iterate over it in the call to `dict()` (the implementation of `dict(listOfTuples)` has to consume the list via iteration), then iterate over the dictionary via `.items()`. There are two full iterations of the data. Mine only iterates that inner-most list once time. – g.d.d.c Sep 06 '18 at 01:15
  • You're absolutely right. Thanks a lot for the clarification! – shahbazkhan Sep 06 '18 at 01:34
0

Playing around with 3rd party Pandas, you can do quite a bit with pd.read_csv:

import pandas as pd

s = 'us:0.9,can:1.2,mex:0.45'

d = pd.read_csv(pd.compat.StringIO(s), sep=':', header=None, lineterminator=',')\
      .set_index(0)[1].to_dict()

{'us': 0.9, 'can': 1.2, 'mex': 0.45}
jpp
  • 159,742
  • 34
  • 281
  • 339