Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter common sub-dictionary keys in a dictionary

How do i filter all common sub dictionary keys that exists in other sub dictionary keys in the parent dictionary

d = {
  '0': {'key_x': 0, 'key_y': 15, 'key_z': 41}
  '1': {'key_x': 5, 'key_y': 22}
  '2': {'key_x': 6, 'key_y': 41}
}

result ['key_x', 'key_y']

current solution is

intersect = {}
for k in corner_values.keys():
    for j in corner_values[k]:
        if j not in intersect:
            intersect[j] = 1
        else:
            intersect[j] += 1

for k in intersect:
    if intersect[k] != len(corner_values.keys()):
        del intersect[k]

Is there any simpler solution for this?

like image 285
PYPL Avatar asked Jan 06 '23 05:01

PYPL


2 Answers

You can map the dictionaries to set and then reduce using set.intersection:

>>> from functools import reduce # if you are using Python 3
>>> d = {                       
...   '0': {'key_x': 0, 'key_y': 15, 'key_z': 41},
...   '1': {'key_x': 5, 'key_y': 22},
...   '2': {'key_x': 6, 'key_y': 41}
... }
>>> reduce(set.intersection, map(set, d.values()))
{'key_x', 'key_y'}

Note: In Python 3, reduce has been moved to functools.

Update: As seen in @John's answer, set.intersection can handle an arbitrary number of sets, so the reduce is not even necessary. Just set.intersection(*map(set, d.values()))

like image 159
tobias_k Avatar answered Jan 18 '23 03:01

tobias_k


You can do a single set.intersection operation once you extract all the keys. It's a one-liner then:

set.intersection(*(set(x) for x in d.itervalues()))

Breaking that down, the first part evaluated is this:

(set(x) for x in d.itervalues())

That's a generator which produces:

{'key_x', 'key_y'}, {'key_x', 'key_y', 'key_z'}, {'key_x', 'key_y'}

In Python 3 that generator is equivalent to:

map(set, d.values())

But in Python 2, map is less efficient because it constructs a list that we don't need (as does values() instead of itervalues()).

In any case, the results of that generator are passed to set.intersection (using the * argument unpacker) to do the heavy lifting in a single call.

like image 21
John Zwinck Avatar answered Jan 18 '23 04:01

John Zwinck