4

I have a list type object like:

     f = [77.0, 'USD', 77.95, 
     103.9549, 'EUR', 107.3634,
     128.1884, 'GBP', 132.3915,
     0.7477, 'JPY', 0.777]

I want to create a dictionary like below:

d = 
{'EUR': [103.9549, 107.3634],
'GBP': [128.1884, 132.3915],
'JPY': [0.7477, 0.777],
'USD': [77.0, 77.95]}

I tried to utilize these answers Convert a list to a dictionary in Python, and Make dictionary from list with python.

But, couldn't figure out the right way.

As of now, my solution is:

cs = [str(x) for x in f if type(x) in [str, unicode]]
vs = [float(x) for x in f if type(x) in [int, float]]
d =  dict(zip(cs, [[vs[i],vs[i+1]] for i in range(0,len(vs),2)]))

but, what would be a smart one-liner ?

Community
  • 1
  • 1
kmonsoor
  • 7,600
  • 7
  • 41
  • 55
  • 1
    Is your list structure constant and persistent? I.e. basically you want every 2nd element of 3 be the key and 1st and 3rd as value list? – favoretti May 28 '14 at 14:47
  • @favoretti yes, right – kmonsoor May 28 '14 at 14:48
  • Why do you want a one-liner? You're trying to do something that's not obviously simple here. It might be better to write an actual method so it's easier for people to understand what you're trying to do. There are a lot of things that can be expressed as one-liners that aren't terribly clear...it's python not perl. :) – FrobberOfBits May 28 '14 at 14:48
  • @FrobberOfBits 'cause, imo, conceptually it is just one operation; one dict from two lists. That's why an one-liner should be a more fit. confession: i am an addict of one-liners, which i find "poetic" ;) – kmonsoor May 28 '14 at 17:10
  • @kmonsoor I agree they are poetic and nice, just please consider the perspective of someone who later maintains your code. That guy probably prefers explicit documentation and clear flow, over elegance and economy. It is conceptually just one operation; the function definition (not the one-liner) is usually my go-to for wrapping up a bunch of implementation steps into a single conceptual operation. The language has lots of syntax explicitly to support that in function definitions. – FrobberOfBits May 28 '14 at 17:22
  • @FrobberOfBits i totally agree w/ you ... – kmonsoor May 28 '14 at 17:33

4 Answers4

7

How about:

In [5]: {f[i+1]: [f[i], f[i+2]] for i in range(0, len(f), 3)}
Out[5]: 
{'EUR': [103.9549, 107.3634],
 'GBP': [128.1884, 132.3915],
 'JPY': [0.7477, 0.777],
 'USD': [77.0, 77.95]}
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • @NPE thanks for helping out so promptly. This is THE answer, i was looking for ... :) – kmonsoor May 28 '14 at 17:18
  • 1
    Props to @NPE for coming up with a precise one-liner; NPE answered OP's question. But I don't think this should be done as a one-liner. If I'm maintaining this code, I have to go back to look at an example of the data structure to figure out WTF i+1, i, and i+2 should refer to. At the very least, OP should realize that this code is in desperate need of a comment or two. – FrobberOfBits May 28 '14 at 17:38
2

Using zip, dict comprehension:

>>> f = [
...     77.0, 'USD', 77.95,
...     103.9549, 'EUR', 107.3634,
...     128.1884, 'GBP', 132.3915,
...     0.7477, 'JPY', 0.777
... ]
>>> {currency: [v1, v2] for v1, currency, v2 in zip(*[iter(f)]*3)}
{'JPY': [0.7477, 0.777],
 'USD': [77.0, 77.95],
 'GBP': [128.1884, 132.3915],
 'EUR': [103.9549, 107.3634]}

[iter(f)]*3 came from grouper in itertools recipes.

falsetru
  • 357,413
  • 63
  • 732
  • 636
1

This has to be the ugliest one-liner in the history of one-liners, but hey, it works:

print dict(zip((i[1] for i in zip(f[::3],f[1::3],f[2::3])), ([i[0],i[2]] for i in zip(f[::3],f[1::3],f[2::3]))))
sshashank124
  • 31,495
  • 9
  • 67
  • 76
0
>>> f = [77.0, 'USD', 77.95,
         103.9549,'EUR', 107.3634,
         128.1884, 'GBP', 132.3915,
         0.7477, 'JPY', 0.777]
>>> {f[v+1]:[f[v],f[v+2]] for v in range(0, len(f), 3)}
{'JPY': [0.7477, 0.777], 'USD': [77.0, 77.95], 'GBP': [128.1884, 132.3915], 'EUR': [103.9549, 107.3634]}
Chris Clarke
  • 2,103
  • 2
  • 14
  • 19