4

A function returns two lists which are logically mapped one-to-one. Suppose

name = ["facebook", "twitter", "myspace"]
hits = [4000, 2500, 1800]

Therefore, hits for facebook are 4000, twitter 2500, and myspace 2500.

I want to convert these two separate lists into a list of dictionaries like

[
  {name: 'facebook',data: [4000]},
  {name: 'twitter',data: [2500]},
  {name: 'myspace',data: [1800]}
]

My solution to do this is:

data = [
    {"name":l, "data":[v]}
    for idx1, l in enumerate(labels)
    for idx2, v in enumerate(values)
    if idx1 == idx2
    ]

Is there a more elegant way of dealing with logical one-to-one mapping or is my solution precise?

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
Zain Khan
  • 3,753
  • 3
  • 31
  • 54
  • 1
    [zip](http://docs.python.org/library/functions.html#zip) is the little nugget of elegance you're looking for. – tylerl Dec 22 '11 at 07:18
  • 1
    Does your example really embody a one-to-one relationship? Isn't it possible that both *twitter* and *myspace* have the same number of hits? – Raymond Hettinger Dec 22 '11 at 08:22
  • @RaymondHettinger: the question illustrates a logical mapping. Meaning name [0] is mapped to hits[0] and so on – Zain Khan Dec 22 '11 at 08:57
  • 2
    @mangobug Then your answer is as simple as ``name2hits = dict(zip(name, hits))``. There is no need for separate *name* and *data* fields, nor for a list of values. Also, the term "one-to-one" can be dropped (as that term implies an injective mathematical function). – Raymond Hettinger Dec 22 '11 at 09:10

3 Answers3

12

You could do:

[{"name": n, "data": [h]} for n, h in zip(name, hits)]

While this does what you asked for, there's probably more data structure here than you really need. Consider:

>>> dict(zip(name, hits))
{'twitter': 2500, 'myspace': 1800, 'facebook': 4000}

This provides the same data set in an easier-to-access data structure.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • This is what the OP asked for, but it is *far* from being the right data structure for his task. The *name* and *data* key fields are a waste and so is the inner list which isn't necessary either. – Raymond Hettinger Dec 23 '11 at 18:12
4

The simplest and fastest way to handle one-to-one relationships is to make two dictionaries:

>>> name = ["facebook", "twitter", "myspace"]
>>> hits = [4000, 2500, 1800]
>>> name2hits = dict(zip(name, hits))
>>> hit2name = dict(zip(hits, name))
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
0

Similar but not exactly the same as Efficient bidirectional hash table in Python?

You should just use two dictionaries, and when you make an update, apply the update to both.

Also, there is a logical inconsistency here: Either your function is not one-to-one, or you have no need for keeping data: [...] in a list since there can only be one value.

If you really need to convert it into a list of dictionaries, use zip as pointed out in https://stackoverflow.com/a/8600534/711085

Community
  • 1
  • 1
ninjagecko
  • 88,546
  • 24
  • 137
  • 145