Liyuan Liu
Liyuan Liu

Reputation: 105

How to use filter in python to filter a dictionary in this situation?

I never used python before. Now I have a dictionary like :

d1 = {1:2,3:3,2:2,4:2,5:2}

The pair[0] in each pair means point, the pair[1] in each pair means the cluster id. So d1 means point 1 belongs to cluster 2, point 3 belongs to cluster 3, point 2 belongs to cluster 2, point 4 belongs to cluster 2, point 5 belongs to cluster 2. No point belongs to cluster 1. How to use filter(don't use loop) to get a dictionary like following :

d2 = {1:[],2:[1,2,4,5],3:[3]}

it means no point belongs to cluster 1, 1,2,4,5 belongs to cluster 2, 3 belongs to cluster 3. I tried :

d2 = dict(filter(lambda a,b: a,b if a[1] == b[1] , d1.items()))

Upvotes: 1

Views: 175

Answers (2)

mgilson
mgilson

Reputation: 310237

I would use a collections.defaultdict

from collections import defaultdict

d2 = defaultdict(list)
for point, cluster in d1.items():
    d2[cluster].append(point)

Your defaultdict won't have a cluster 1 in it, but if you know what clusters you expect, then all will be fine with the world (because the empty list will be put in that slot when you try to look there -- this is the "default" part of the defaultdict):

expected_clusters = [1, 2, 3]
for cluster in expected_clusters:
    print(d2[cluster])

FWIW, doing this problem with the builtin filter is just insanity. However, if you must, something like the following works:

d2 = {}
filter(lambda (pt, cl): d2.setdefault(cl, []).append(pt), d1.items())

Note that I'm using python2.x's unpacking of arguments. For python3.x, you'd need to do something like lambda item: d2.setdefault(item[1], []).append(item[0]), or, maybe we could do something like this which is a bit nicer:

d2 = {}
filter(lambda pt: d2.setdefault(d1[pt], []).append(pt), d1)

We can do a tiny bit better with the reduce builtin (at least the reduce isn't simply a vehicle to create an implicit loop and therefore actually returns the dict we want):

>>> d1 = {1:2,3:3,2:2,4:2,5:2}
>>> reduce(lambda d, k: d.setdefault(d1[k], []).append(k) or d, d1, {})
{2: [1, 2, 4, 5], 3: [3]}

But this is still really ugly python.

Upvotes: 2

saikumarm
saikumarm

Reputation: 1575

>>> d1 = {1:2,3:3,2:2,4:2,5:2}
>>> dict(map(lambda c : (c, [k for k, v in d1.items() if v == c]), d1.values()))
{2: [1, 2, 4, 5], 3: [3]}
  1. lambda function to get the value list
  2. map function to map values(clusters) using the above lambda

Upvotes: 0

Related Questions