-1

I have dictionaries in a list with same keys, while the values are variant:

[{1:[1,2,3,4,5], 2:[6,7,8], 3:[1,3,5,7,9]},
 {1:[2,3,4], 2:[6,7], 3:[1,3,5]},
 ...]

I would like to get intersection as dictionary under same keys like this:

{1:[2,3,4], 2:[6,7], 3:[1,3,5]}
m00am
  • 5,910
  • 11
  • 53
  • 69
Fei-man Hsu
  • 165
  • 8
  • Do you have just 2 items that you want to intersect or could your list of dict have more than just 2 items? – mgilson Jul 15 '16 at 07:49
  • I've tried: set(mylist[0][key]).intersection(*mylist[1:][key]) but got error message "list index out of range". I have in total 12 dictionaries in the list. – Fei-man Hsu Jul 15 '16 at 07:52
  • You could gather all lists for a specific key, e.g. `lists` and then do `list(set.intersection(*map(set, lists)))`. If you do this for all keys you basically have what you desire. Do you need a fixed order in your "values"? If not, you could consider making them `set`s in the first place. Then, it would come down to `set.intersection(*sets)` after gathering all sets for a specific key in the variable `sets`. – Michael Hoff Jul 15 '16 at 07:53

4 Answers4

0

Give this a try?

dicts = [{1:[1,2,3,4,5], 2:[6,7,8], 3:[1,3,5,7,9]},{1:[2,3,4], 2:[6,7], 3:[1,3,5]}]

result = { k: set(dicts[0][k]).intersection(*(d[k] for d in dicts[1:])) for k in dicts[0].keys() }

print(result)

# Output:
# {1: {2, 3, 4}, 2: {6, 7}, 3: {1, 3, 5}}

If you want lists instead of sets as the output value type, just throw a list(...) around the set intersection.

user94559
  • 59,196
  • 6
  • 103
  • 103
0

For a list of dictionaries, reduce the whole list as this:

>>> from functools import reduce
>>> d = [{1:[1,2,3,4,5], 2:[6,7,8], 3:[1,3,5,7,9]},{1:[2,3,4], 2:[6,7], 3:[1,3,5]}]
>>> reduce(lambda x, y: {k: sorted(list(set(x[k])&set(y[k]))) for k in x.keys()}, d)
{1: [2, 3, 4], 2: [6, 7], 3: [1, 3, 5]}
Netwave
  • 40,134
  • 6
  • 50
  • 93
0

I would probably do something along these lines:

# Take the first dict and convert the values to `set`.
output = {k: set(v) for k, v in dictionaries[0].items()}

# For the rest of the dicts, update the set at a given key by intersecting it with each of the other lists that have the same key.
for d in dictionaries[1:]:
    for k, v in output.items():
        output[k] = v.intersection(d[k])

There are different variations on this same theme, but I find this one to be about as simple to read as it gets (and since code is read more often than it is written, I consider that a win :-)

mgilson
  • 300,191
  • 65
  • 633
  • 696
0

use dict.viewkeys and dict.viewitems

In [103]: dict.viewkeys?
Docstring: D.viewkeys() -> a set-like object providing a view on D's keys

dict.viewitems?
Docstring: D.viewitems() -> a set-like object providing a view on D's items

a = [{1: [1, 2, 3, 4, 5], 2: [6, 7, 8], 3: [1, 3, 5, 7, 9]},
 {1: [2, 3, 4], 2: [6, 7], 3: [1, 3, 5]}]

In [100]: dict(zip(a[0].viewkeys() and a[1].viewkeys(), a[0].viewvalues() and a[1].viewvalues()))
Out[100]: {1: [2, 3, 4], 2: [6, 7], 3: [1, 3, 5]}
Community
  • 1
  • 1
Vishnu Upadhyay
  • 5,043
  • 1
  • 13
  • 24