winklerrr
winklerrr

Reputation: 14727

Mapping over a list nested inside a dict

Data

I'm curious if I can transform the following data

old_data = {
  "key0": [obj0, obj1],
  "key1": [obj2, obj3]
}

to

data = {
  "key0": [obj0.id, obj1.id],
  "key1": [obj2.id, obj3.id]
}

using dict comprehension.

So basically just replacing those list objects with a single attribute of the object itself. All the objects are from the same type and therefore have the id attribute for sure.

Dict comprehension

I came up with the following solution which doesn't work:

data = {
  key: [obj.id]
  for key, obj_list in old_data.items()
  for obj in obj_list
}

Problem

The resulting dictionary just contains lists with exactly one value (the last value which was iterated) because of this line:

key: [obj.id]

creates every time just a new list with one value.

So I instead of creating a new list, I wanted to append new obj_ids to an existing list, but I don't know how. I think it must look somehow like this:

key: data[key].append(obj.id)

But obviously this also can't work because data isn't assigned yet and even if it would be: the first obj.id couldn't be appended because the list was never initialized.

(I'm using Python 3.7)

Upvotes: 0

Views: 465

Answers (2)

Matias Cicero
Matias Cicero

Reputation: 26281

Functional approach

Here's a not so very pythonic, but still interesting way of doing it:

from functools import partial
from operator import attrgetter

old_data = {
  "key0": [obj0, obj1],
  "key1": [obj2, obj3]
}

data = dict(zip(old_data, map(list, map(partial(map, attrgetter('id')), old_data.values()))))

Upvotes: 1

winklerrr
winklerrr

Reputation: 14727

List comprehension

So I found a solution using list comprehension:

data = {
  key: [obj.id for obj in obj_list]
  for key, obj_list in old_data.items()      
}

Just had to move the loop (for obj in obj_list) inside the list comprehension.

This also solves the problem that for the first obj no list exists and further that no other objs need the append method or something like this.

Upvotes: 0

Related Questions