Перераспределить списки значений словаря - PullRequest
0 голосов
/ 15 мая 2018

У меня есть следующий дикт:

groups = {"group 1": [1, 2, 3, 4],
          "group 2": [5, 6, 7, 8],
          "group 3": [9, 10, 11, 12],
          "group 4": [13, 14]}

Когда длина группы меньше минимального размера (group_size=4), я хочу перераспределить участников в другие группы.В этом случае результат будет примерно таким:

groups = {"group 1": [1, 2, 3, 4, 13],
          "group 2": [5, 6, 7, 8, 14],
          "group 3": [9, 10, 11, 12]}

У меня есть следующий код, который работает, но менее эффективен, чем хотелось бы:

# Identify small groups
small_groups = []
for group_name, group_members in groups.items():
    if len(group_members) < group_size:
        small_groups.append(group_name)

# Redistribute members of small groups to the larger groups
to_redistribute = []
for group_name in small_groups:
    to_redistribute.extend(groups.pop(group_name))

for group_name, group_members in groups.items():
    if not to_redistribute:
        break
    group_members.append(to_redistribute.pop())

Важное примечание:Настоящие члены групп - это строки, а не целые числа.

Есть ли лучший способ перераспределения списков значений словаря?

Ответы [ 2 ]

0 голосов
/ 15 мая 2018
  1. Используйте filter и sum для извлечения составных списков длиной менее 4
  2. Используйте понимание, чтобы перестроить новый словарь со списками, длина которых больше или равна 4
  3. повторное удаление одного элемента из отфильтрованного списка и добавление его во вновь созданный ключ словаря, пока все элементы из отфильтрованного списка не будут исчерпаны.

from itertools import cycle

f = lambda v: len(v) < 4
x = sum(filter(f, groups.values()), [])
g = {k: v for k, v in groups.items() if not f(v)}

c = cycle(g)
while x:
    g[next(c)].append(x.pop())

g

{'group 1': [1, 2, 3, 4, 14],
 'group 2': [5, 6, 7, 8, 13],
 'group 3': [9, 10, 11, 12]}
0 голосов
/ 15 мая 2018

Ваше решение хорошо, но вы можете объединить логику всплывающих окон и перераспределения, используя itertools.cycle.

from itertools import cycle

for k in list(groups.keys()):
    if len(groups[k]) < group_size:
        for v, k_ in zip(groups.pop(k), cycle(groups.keys())):
            groups[k_].append(v)

Идея состоит в том, чтобы продолжать циклически переключаться между ключами для равномерного распределения данных.Он определяет - на каждой итерации - находится ли группа за порогом или нет.Если группа действительна, то ее дальнейшее увеличение (посредством перераспределения) никогда не приведет к порогу.Однако группы, которые изначально находятся под порогом (но не будут достигнуты позднее во время будущих итераций), могут стать действительными, если и когда вы увеличите значения из другой группы, которая была удалена.Если этого не произойдет, то он будет удален и его данные будут перераспределены на будущей итерации.

Имейте в виду, что группы, которые первоначально были запланированы для удаления , теперь могут стать действительными после перераспределения,поэтому наши решения будут отличаться по выходу для некоторых входов.

print(groups)
{'group 1': [1, 2, 3, 4, 13],
 'group 2': [5, 6, 7, 8, 14],
 'group 3': [9, 10, 11, 12]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...