使用列表推导创建指定的词典列表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用列表推导创建指定的词典列表相关的知识,希望对你有一定的参考价值。

我有词典列表:

test_users = [{'user': 'ADMIN0', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_512'},
          {'user': 'ADMIN1', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_256'}, 
          {'user': 'MONITOR12', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_512'}, 
          {'user': 'MONITOR13', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_256'}]

并且想要创建一个包含dicts的新列表,其中包含'privilege'和'auth_protocol'的唯一值。例如:

selected_users= [{'user': 'ADMIN0', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_512'},
          {'user': 'MONITOR13', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_256'}, 

限制:

1.'privilege'永远不会重复,

2.(可选)只有在使用所有可能性时才能重复'auth_protocol'(在这种情况下,它可以是'SHA_256'或'SHA_512'中'auth_protocol'的另一个特权)

我试图解决这个问题:

test_users_copy = test_users
selected_users = []
random_user = random.choice(test_users_copy)
# Add randomly chosen user to the list
selected_users.append(random_user)
test_users_copy.remove(random_user)

for test in selected_users:
    selected_users += [user for user in test_users_copy if (user.get('privilege') not in test.get('privilege')) and (user.get('auth_protocol') not in test.get('auth_protocol'))]
答案

如果您只想选择具有不同privileges和auth_protocols的用户:

>>> test_users = [{'user': 'ADMIN0', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_512'},
... {'user': 'ADMIN1', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_256'},
... {'user': 'MONITOR12', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_512'},
... {'user': 'MONITOR13', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_256'}]

>>> privileges, auth_protocols = set(), set()
>>> [tu for tu in test_users if not (tu["privilege"] in privileges or tu["auth_protocol"] in auth_protocols) and not privileges.add(tu["privilege"]) and not auth_protocols.add(tu["auth_protocol"])]
[{'user': 'ADMIN0', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_512'}, {'user': 'MONITOR13', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_256'}]

列表理解非常简单:如果看到tu["privilege"]tu["auth_protocol"],跳过dict;否则将它们添加到所见的权限和auth_protocols(not x.add(y)总是True:这是在列表理解中可以接受副作用的极少数情况之一)。

但是如果您没有不同的协议,这将不会通过特权返回字典。更糟糕的是,选择总是一样的。

要坚持您的可选要求,您需要更复杂的东西。

让我们建立一个字母privilege -> auth_protocol -> users

>>> users_by_ap_by_privilege = {}
>>> for tu in test_users:
...     users_by_ap_by_privilege.setdefault(tu["privilege"], {}).setdefault(tu["auth_protocol"], []).append(tu)
>>> users_by_ap_by_privilege
{'ADMIN': {'SHA_512': [{'user': 'ADMIN0', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_512'}], 'SHA_256': [{'user': 'ADMIN1', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_256'}]}, 'MONITOR': {'SHA_512': [{'user': 'MONITOR12', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_512'}], 'SHA_256': [{'user': 'MONITOR13', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_256'}]}}

我们想要每个privilege(条件1)使用一个用户,并且最大可能不同的auth_protocols(条件2)。

我们可以通过auth_protocol获得privileges:

>>> ap_by_privilege = {privilege: users_by_ap.keys() for privilege, users_by_ap in users_by_ap_by_privilege.items()}
>>> ap_by_privilege
{'ADMIN': dict_keys(['SHA_512', 'SHA_256']), 'MONITOR': dict_keys(['SHA_512', 'SHA_256'])}

对于Python <3.6,我们需要为privileges的所有顺序设置一次(在Python中不会造成任何伤害> = 3.6):

>>> privileges = list(ap_by_privilege)
>>> privileges
['ADMIN', 'MONITOR']

现在很容易构建auth_protocols的所有组合:

>>> import itertools
>>> prod=list(itertools.product(*[ap_by_privilege[p] for p in privileges]))
>>> prod
[('SHA_512', 'SHA_512'), ('SHA_512', 'SHA_256'), ('SHA_256', 'SHA_512'), ('SHA_256', 'SHA_256')]

(注意,元组包含与列表auth_protocol中的每个privilege相关联的privilegess,顺序相同)我们现在可以影响每个组合的重复计数:

>>> import collections
>>> tuples_by_dup_count = {}
>>> for t in prod:
...     tuples_by_dup_count.setdefault(max(collections.Counter(t).values()), []).append(t)
...
>>> tuples_by_dup_count
{2: [('SHA_512', 'SHA_512'), ('SHA_256', 'SHA_256')], 1: [('SHA_512', 'SHA_256'), ('SHA_256', 'SHA_512')]}

现在,我们采用这个dict的最小键,即具有最小重复数的元组(条件2):

>>> ts = tuples_by_dup_count[min(tuples_by_dup_count)]
>>> ts
[('SHA_512', 'SHA_256'), ('SHA_256', 'SHA_512')]

然后我们选择auth_protocols的组合:

>>> import random
>>> t = random.choice(ts)
>>> t
('SHA_256', 'SHA_512')

并使用它来选择privilege / auth_protocol的随机用户:

>>> [random.choice(users_by_ap_by_privilege[p][t[i]]) for i, p in enumerate(privileges)]
[{'user': 'ADMIN0', 'privilege': 'ADMIN', 'auth_protocol': 'SHA_512'}, {'user': 'MONITOR13', 'privilege': 'MONITOR', 'auth_protocol': 'SHA_256'}]

以上是关于使用列表推导创建指定的词典列表的主要内容,如果未能解决你的问题,请参考以下文章

使用 if 和 break 创建 Python 列表推导式

python中的列表推导式

测开之数据类型进阶篇・第三篇《推导式》

列表推导式和生成器

九九乘法表 列表推导式

Python推导式尝试学习