Warm tip: This article is reproduced from serverfault.com, please click

Remove certain elements in a list of dicts

发布于 2020-11-28 13:37:27

I have the following list of dicts as follows:

l1=[{"key1":"a1","key2":"a2"}, {"key1":"b1","key2":"b2"},
    {"key1":"c1","key2":"c2"}, {"key1":"a2","key2":"a1"},
    {"key1":"c2","key2":"c1"}, ....]

I want to remove the repeated elements in the dict.For example,if I have a1 and a2, once in the list of dicts,I don't want them again.So,in the above example,I don't want the dicts

{"key1":"a2","key2":"a1"},{"key1":"c2","key2":"c1"}

How do I delete them? Basically I want to remove the dicts having same values irrespective of their order. I have tried the following code:

for i in range(0,len(l1)):
  for key,val in l1[i].items():
      if l[i][key]==l[i+1][key]
         del l[i+1][key]

This doesn't work

Questioner
Sam
Viewed
0
Patrick Artner 2020-11-28 23:15:17

Use a defaultdict(list) to collect under keys of frozenset of the values of your source list inner dict's and collect the actual dicts as values.

Iterate the defaultdict(list) and keep f.e. the 1st entry of each of its value lists:

l1=[{"key1":"a1","key2":"a2"},{"key1":"b1","key2":"b2"},
    {"key1":"c1","key2":"c2"},{"key1":"a2","key2":"a1"},
    {"key1":"c2","key2":"c1"}]

from collections import defaultdict
d = defaultdict(list)

# store dicts under the values of itself - use frozendict for key to 
# ignore order of values 
for inner in l1:
    d[frozenset(inner.values())].append(inner)

# construct new dict by f.e. keeping the first dict out of each list
l2 = [v[0] for _,v in d.items()] 

# pretty print them
from pprint import pprint
pprint(d)
pprint(l2) 

Output:

# intermediate dict
defaultdict(<class 'list'>,
            {frozenset({'a1', 'a2'}): [{'key1': 'a1', 'key2': 'a2'},
                                       {'key1': 'a2', 'key2': 'a1'}],
             frozenset({'b2', 'b1'}): [{'key1': 'b1', 'key2': 'b2'}],
             frozenset({'c1', 'c2'}): [{'key1': 'c1', 'key2': 'c2'},
                                       {'key1': 'c2', 'key2': 'c1'}]})
# resulting dict
[{'key1': 'a1', 'key2': 'a2'},
 {'key1': 'b1', 'key2': 'b2'},
 {'key1': 'c1', 'key2': 'c2'}]

See defaultdict abd pretty printer


In case you can not use defaultdict, you can use a normal one as well - it is just not as performant:

d = {}
for inner in l1:  
    d.setdefault(frozenset(inner.values()),[]).append(inner)