简体   繁体   English

组合具有不同值的字典列表

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM