[英]Combine lists of dictionaries with different values
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.我需要将所有匹配的键与
dicts
中的值组合在一起,如果某些key
为真,则其给定的优先级高于假。
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我的尝试假设列表是基于键排序的,我有一个变量 x 来知道一个键在列表中重复了多少次
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.这部分有效,看起来也不是最干净的。
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 = {'account_general_permission': Counter(), 'control_section_permission': Counter()}
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: output:
{'account_general_permission': {'view': True, 'create': True, 'edit': True, 'delete': False}},
{'control_section_permission': {'view': False, 'create': False, 'edit': False, 'delete': False}}
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:使用
pandas
进行的过度杀伤,但单行可能如下所示:
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}}
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.结果是一个 dicts 的 dict,但我觉得它对于这个任务来说是一个更自然的数据结构。
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.我不知道 numpy 的东西,但你的例子应用于原始列表已经是合理的,特别是考虑到这是一个小数据集。 Iteration is faster than indexing and a dictionary's update function that is written in C is a bit faster still.
迭代比索引更快,并且字典的更新 function 是用 C 编写的,但速度还是要快一些。 So, using a
defaultdict
to create items as needed, you could do因此,使用
defaultdict
根据需要创建项目,您可以这样做
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.此解决方案不会更新原始表中的字典。
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)
return {p: any(d.get(p) for d in (d, unwrappe_d))
for p in unwrappe_d}
grouped = groupby(sorted(lod, key=get_key), get_key)
result = [{p: reduce(merge_dicts, perm_dicts, {})}
for p, perm_dicts in grouped]
This one also depends on all the "inner keys" ( 'view'
, 'edit'
etc) present.这也取决于存在的所有“内部键”(
'view'
、 'edit'
等)。 I'll think on how it could be improved.我会考虑如何改进它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.