Создать заданный список словарей со списком пониманий - PullRequest
0 голосов
/ 21 апреля 2019

У меня есть список словарей:

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

и хочу создать новый список с диктовками, который содержит уникальные значения «privilege» и «auth_protocol». Например:

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

Ограничения:

1. «Привилегия» никогда не может быть дублирована,

2. (Необязательно) «auth_protocol» может повторяться, только если используются все возможности (в этом случае это может быть другая привилегия с «auth_protocol» в «SHA_256» или «SHA_512»)

Моя попытка решить проблему:

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

1 Ответ

0 голосов
/ 23 апреля 2019

Если вы просто хотите выбрать пользователей с разными privilege с и auth_protocol с:

>>> 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_protocol с (условие 2).

Мы можем иметь в наличии auth_protocol s privilege:

>>> 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 нам нужно установить один раз для всех порядка <code>privilege с (не причинит никакого вреда в Python> = 3.6):

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

Теперь легко создавать все комбинации auth_protocol s:

>>> 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 в списке privileges, в том же порядке). Теперь мы можем повлиять на количество дубликатов для каждой комбинации:

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

Теперь мы берем минимальный ключ этого диктанта, то есть кортежи с минимальным количеством дубликатов (условие 2):

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

Затем мы выбираем комбинацию auth_protocol с:

>>> 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'}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...