简体   繁体   English

将相同的值与Python中的字典列表组合

[英]Combining identical values against a list of dictionaries in Python

I am building a table using python. 我正在使用python构建表。 The rows to the table are contained in a list of a dictionaries, like so: 该表的行包含在词典列表中,如下所示:

table = [{ 'User' : 'johndoe', 'Profile' : 'Production', 'Risk' : 'No MFA', 'Action': 'Disable account and notify user' }, 
         { 'User' : 'janedoe', 'Profile' : 'Production', 'Risk' : 'Expired Password', 'Action': 'Reset password and notify user' },
         { 'User' : 'cookiedoe', 'Profile' : 'Non-Production', 'Risk' : 'Expired key', 'Action': 'Delete old key and notify user' },]

I run a function to build the row each time I detect a non-compliant condition. 每当我检测到不符合条件时,我都会运行一个函数来构建行。 My goal is to combine rows where 'User' and 'Profile' are identical. 我的目标是合并“用户”和“个人资料”相同的行。 For instance, if johndoe in Production also had an expired password, I want his dictionary to look thusly: 例如,如果Production中的johndoe也有过期的密码,那么我希望他的字典看起来像这样:

{ 'User' : 'johndoe', 'Profile' : 'Production', 'Risk' : 'No MFA, Expired password', Action: 'Disable account and notify user\n Reset password and notify user' }

Each current row lives in a local dictionary called 'row'. 当前的每一行都生活在称为“行”的本地词典中。 This is how I'm trying to accomplish this now: 这就是我现在想要实现的方式:

for past_row in table:

     past_user = past_row['User']
     row_user = row['User']
     past_profile = past_row['Profile']
     row_profile = row['Profile']

     if past_user == row_user and past_profile == row_profile:

           past_row['Risk'] = "%s, %s" %(past_row['Risk'], row['Risk'])
           past_row['Action'] = "%s\n %s" %(past_row['Action'], row['Action'])

My Python script just runs endlessly, without ever finishing. 我的Python脚本无休止地运行,没有完成。 I feel like I'm examining my past rows inefficiently, and I'm fairly young in my Pythonic education. 我感觉自己在低效率地检查过去的行,而且我还很年轻,接受过Python语言教育。 Googling in circles is just making my logic more convoluted. 围着谷歌搜索只是让我的逻辑更加混乱。 Can someone set me straight? 有人可以让我挺直吗?

Ok, I've come up with a quick solution. 好的,我想出了一个快速的解决方案。 It can be done more efficiently, however, keeping in mind you're a beginner in Python, I placed my bets on readability. 它可以更高效地完成,但是,请记住您是Python的初学者,我将重点放在可读性上。 Here it goes (the script is executable as is): 它就到了(脚本可以按原样执行):

# Import default-dictionary.
from collections import defaultdict

# Minimal sample, we want to merge johndoe.
table = [{ 'User' : 'johndoe', 'Profile' : 'Production', 'Risk' : 'No MFA', 'Action': 'Disable account and notify user' },
         { 'User' : 'johndoe', 'Profile' : 'Production', 'Risk' : 'Expired Password', 'Action': 'Reset password and notify user' },
         { 'User' : 'cookiedoe', 'Profile' : 'Non-Production', 'Risk' : 'Expired key', 'Action': 'Delete old key and notify user' },]


# Inline function definition for combinining risks/actions
# from multiple profiles.
combine_risks = lambda ps: ', '.join([p['Risk'] for p in ps])
combine_actions = lambda ps: ', '.join([p['Action'] for p in ps])

# Merge multiple profile dicts into one.
def combine_profiles(profiles):
    return dict(
        User=profiles[0]['User'],
        Profile=profiles[0]['Profile'],
        Risk=combine_risks(profiles),
        Action=combine_actions(profiles)
    )

# Profile - indices mapping.
prof2ind = defaultdict(set)

# Enumerate profiles and save information about which profiles
# have matching User and Profile.
for index, row in enumerate(table):
    key = (row['User'], row['Profile'])
    prof2ind[key].add(index)

new_table = []

# Finally, build merged table.
# 'indices' is a set holding indices of matching profile-sets.
for indices in prof2ind.values():
    profiles = [table[i] for i in indices]
    new_table.append(combine_profiles(profiles))

# Check the result.
print(new_table)

This script is general in the sense that is works on multiple matching profiles, not only pairs. 从某种意义上说,此脚本是通用的,可用于多个匹配的配置文件,而不仅仅是对。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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