Reputation: 23
I have list of dictionaries with matching keys like this.
[{'account_general_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}]
I need to combine all matching keys together with the value inside the dicts
where if there is true for some key
its given priority over false.
So result should look something like
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}]
What would the fastest way to achieve this as speed is crucial to perform this.
My attempt Assuming list is sort based on keys and I have a variable x to know how many times a key repeats in a list
new_list = np.array_split(new_list, len(permission))
for i in new_list:
for j in i:
for k, l in j.items():
for m, n in l.items():
if n == True:
l[m] = n
This partially works, also doesn't look the cleanest.
Upvotes: 0
Views: 96
Reputation: 1986
Let's get crazy and functional:
lod = [{'account_general_permission': {'view': False, 'create': False, 'edit':
False, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit':
False, 'delete': False}},
{'account_general_permission': {'view': True, 'create': True, 'edit':
True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit':
False, 'delete': False}}]
from functools import reduce
from itertools import groupby
def get_key(d):
return next(iter(d.keys()))
def get_val(d):
return next(iter(d.values()))
def merge_dicts(d, perm_d):
unwrappe_d = get_val(perm_d)
keys = set(d) | set(unwrappe_d)
return {p: any(d.get(p) for d in (d, unwrappe_d))
for p in keys}
grouped = groupby(sorted(lod, key=get_key), get_key)
result = [{p: reduce(merge_dicts, perm_dicts, {})}
for p, perm_dicts in grouped]
Upvotes: 0
Reputation: 3101
this should work
from collections import Counter
data = [{'account_general_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}]
counters = {list(dicto.keys())[0]: Counter() for dicto in data}
for element in data:
for key, data in element.items():
counters[key].update(data)
result = [{key: {item: bool(val) for item, val in data.items()}} for key, data in counters.items()]
result
output:
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}
Upvotes: 1
Reputation: 13242
data = [{'account_general_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}]
# Let's make a new dictionary~
new_data = {}
for x in data:
# Each "dictionary" in your list appears to just be a single key/value pair.
key, values = tuple(x.items())[0]
# If we've added this key to the dictionary already...
if key in new_data:
for k in values:
# If that inner key isn't already True, or doesn't exist.
if not new_data[key].get(k):
# Overwrite this inner key's value OR add the new key:value pair.
new_data[key][k] |= values[k]
# Otherwise we can just add this dict to the new dict.
else:
new_data |= x
print(new_data)
# Output:
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False},
'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}
An overkill, but one-line approached using pandas
could look like:
data = (pd.concat([pd.DataFrame.from_dict(x, 'index') for x in data])
.groupby(level=0)
.max()
.to_dict('index'))
print(data)
# Output
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False},
'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}
Upvotes: 0
Reputation: 77347
I don't know about the numpy stuff, but your example applied to the original list is already reasonable, especially considering that this is a small data set. Iteration is faster than indexing and a dictionary's update function that is written in C is a bit faster still. So, using a defaultdict
to create items as needed, you could do
import collections
data = [{'account_general_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}},
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}]
resolved = collections.defaultdict(lambda: {'view': False, 'create': False,
'edit': False, 'delete': False})
for perms in data:
for perm_name, perm_vals in perms.items():
resolved[perm_name].update((n,v) for n,v in perm_vals.items() if v)
for k,v in resolved.items():
print(f"{k}: {v}")
This solution does not update the dictionaries in the original table.
Upvotes: 0
Reputation: 1986
lod = [{'account_general_permission': {'view': False, 'create': False, 'edit':
False, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit':
False, 'delete': False}},
{'account_general_permission': {'view': True, 'create': True, 'edit':
True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit':
False, 'delete': False}}]
result = {}
for d in lod:
perm_name, perms = next(iter(d.items()))
result[perm_name] = {perm_elem: any([perm_val,
result.get(perm_name, {}
).get(perm_elem, False)])
for perm_elem, perm_val in perms.items()}
{'account_general_permission': {'create': True,
'delete': False,
'edit': True,
'view': True},
'control_section_permission': {'create': False,
'delete': False,
'edit': False,
'view': False}}
The result is a dict of dicts, though, but I feel like it's a more natural data structure for this task.
Upvotes: 0