【问题标题】:Create specified list of dictionaries with list comprehensions使用列表推导创建指定的字典列表
【发布时间】:2019-04-21 15:45:42
【问题描述】:

我有字典列表:

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'}]

并且想要创建一个包含“特权”和“auth_protocol”唯一值的字典的新列表。例如:

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

限制:

1.'特权'永远不能被复制,

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'))]

【问题讨论】:

  • 如果出现重复的privilege 或auth_protocol,您如何决定选择哪个字典
  • 将所有元素添加到带有键 (privilege, auth_protocol) 的中间字典,并将其 values() 转换为列表。
  • 特权应该始终是唯一的(如果没有更多唯一的“特权”列表完成),但是“auth_protocol”的值应该尽可能多样化,所以我会检查 selected_users 中的当前值并在此基础上做出选择。
  • 那么带有ADMIN1 和MONITOR12 的字典会被删除吗?此外,您的文字描述没有多大意义,最好能提供具体的输出
  • 代码将出现在函数中,每次它适用于所有创建的用户的副本。这样做的目的是获取随机用户及其参数(由 dicts 表示)最终输出将包含具有唯一权限的字典列表,因此列表中 dics 的总数将等于唯一权限。我之前发布了示例输出(selected_users)。添加后删除dict显然是因为无法再次使用相同的权限

标签: python list dictionary for-loop


【解决方案1】:

如果您只想选择具有不同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"],则跳过字典;否则将它们添加到所见特权和 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)。

我们可以通过privilege获得可用的auth_protocols:

>>> 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 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')]

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

>>> 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'}]

【讨论】:

    猜你喜欢
    • 2021-05-01
    • 2016-02-04
    • 2018-07-24
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    相关资源
    最近更新 更多