Исправить вывод с помощью itertools.groupby

#python #group-by #itertools

#python #сгруппировать по #python-itertools

Вопрос:

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

Кроме того: как я могу сделать это более эффективным. Как я могу сделать это без использования явных циклов, но вместо этого использовать понимание списка / словаря.

Это то, что я делаю:

 def group_permutation_values(permutations_list): 

    dic = {}
    f = lambda x: x[1]
    for key, group in itertools.groupby(sorted(permutations_list, key=f), f):
        dic[key] = list(group)

    return dic

    pass

results = [
    ((1, 2, 3), -4),
    ((1, 3, 2), -4),
    ((2, 1, 3), -2),
    ((2, 3, 1), -2),
    ((3, 1, 2), 0), 
    ((3, 2, 1), 0)
]
print(group_permutation_values(results))
  

Это то, что я получил:

 {
    -4: [((1, 2, 3), -4), ((1, 3, 2), -4)],
    -2: [((2, 1, 3), -2), ((2, 3, 1), -2)],
     0: [((3, 1, 2), 0), ((3, 2, 1), 0)]
}
  

И ожидаемый результат:

 {
    -4: [(1, 2, 3), (1, 3, 2)],
    -2: [(2, 1, 3), (2, 3, 1)],
     0: [(3, 1, 2), (3, 2, 1)]
}
  

Комментарии:

1. Пожалуйста, не создавайте больше работы для других людей, вандализируя свои сообщения. Публикуя в сети Stack Exchange, вы предоставляете Stack Exchange право, не подлежащее отзыву, в соответствии с лицензией CC BY-SA 3.0 , распространять этот контент (т. Е. Независимо от вашего будущего выбора). Согласно политике обмена стеками, распространяется версия post, не подвергшаяся вандализму. Таким образом, любой вандализм будет отменен. Если вы хотите узнать больше об удалении записи, пожалуйста, смотрите: Как работает удаление?

Ответ №1:

Ключевая функция groupby только определяет, как группируются значения; функция не используется для изменения самих элементов группы. То, что вы группируете по element[1] , не означает, что группы будут содержать только element[0] , вы получите весь кортеж.

Все, что вам нужно сделать, это извлечь этот первый вложенный кортеж из каждого элемента группы при создании вашего значения списка:

 dic[key] = [t[0] for t in group]
  

итак, где list(group) возвращается [((1, 2, 3), -4), ((1, 3, 2), -4)] , вместо этого создается приведенное выше понимание списка [(1, 2, 3), (1, 3, 2)] .

Вы можете заменить свой внешний for цикл, создающий словарь на основе groupby результатов, пониманием словаря:

 def group_permutation_values(permutations_list): 
    f = lambda x: x[1]
    sorted_list = sorted(permutations_list, key=f)
    return {k: [t[0] for t in g] for k, g in itertools.groupby(sorted_list, f)}
  

Однако использование groupby() здесь является неправильным инструментом. groupby() требуется, чтобы вы сначала отсортировали входные данные, что снижает производительность. Сортировка — это операция O (N log N), но вместо этого объединение ваших кортежей в словарь может быть выполнено за O (N) линейное время просто путем перебора вашего списка ввода и добавления в список каждой записи:

 def group_permutation_values(permutations_list):
    grouped = {}
    for a, b in permutations_list:
        grouped.setdefault(b, []).append(a)
    return grouped
  

Это не может быть превращено в понимание по словарю, но, тем не менее, более эффективно. Понимания — это не волшебные пули, это просто синтаксис для создания контейнеров (списков, словарей, наборов) путем обработки каждого элемента из итерируемого. Да, они немного более эффективны, чем эквивалентная операция for с циклом добавления в контейнер, но они по-прежнему подвержены обычным алгоритмическим временным сложностям.