Python динамически вычисляет список без дубликатов, используя только списки - PullRequest
0 голосов
/ 18 декабря 2018

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

"reading_types": [
    {
        "name": rt.reading_type,
        "value": rt.reading_type_id,
    }
    for unit in item.units
    for rt in unit.reading_types
],

в вызове API бэкэнда.Это прекрасно работает за исключением , что почти всегда будут дубликаты в конечном результате.Как я могу гарантировать, что дубликаты не будут возвращены?

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

Я пыталсяиспользуя set:

set([
    {
        "name": rt.reading_type,
        "value": rt.reading_type_id,
    }
    for unit in item.units
    for rt in unit.reading_types
])

, но это приводит к ошибке: unhashable type: dict

Ответы [ 4 ]

0 голосов
/ 18 декабря 2018

Это не список, но вы можете использовать рецепт itertools unique_everseen , также доступный в сторонних библиотеках, например, more_itertools.unique_everseen:

from more_itertools import unique_everseen

input_list = [{"name":"name1","id":"id1"},{"name":"name2","id":"id2"},
              {"name":"name1","id":"id1"}]

res = list(unique_everseen(input_list, key=lambda d: tuple(sorted(d.items()))))

print(res)

[{'name': 'name1', 'id': 'id1'}, {'name': 'name2', 'id': 'id2'}]

Хитрость заключается в том, чтобы убедиться, что вы можете хэшировать свои словари, что мы и выполняем путем преобразования каждого словаря в кортеж отсортированных кортежей.Внутри алгоритм работает, поддерживая «видимые» set значений и получая только те значения, которые не отображаются в set, добавляя их в противном случае.

0 голосов
/ 18 декабря 2018

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

Вы можете преобразовать свои словари в dict_items, а затем вtuples (теперь мы можем поместить это в set, потому что данные можно хэшировать), применить к нему set и преобразовать обратно в словарь:

input_list = [{"name":"name1","id":"id1"},{"name":"name2","id":"id2"},
{"name":"name1","id":"id1"}]

output_list = [dict(items) for items in {tuple(a.items()) for a in input_list}]

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

результат:

[{'id': 'id1', 'name': 'name1'}, {'id': 'id2', 'name': 'name2'}]

другое решение (от Jon Clements), которое не использует set, но создаетсловарь (с использованием словарного понимания) & использует уникальность ключа для дублирования дубликатов, а затем извлекает только значения:

list({tuple(d.items()):d for d in input_list}.values())
0 голосов
/ 18 декабря 2018

Вы можете использовать namedtuple вместо словаря внутри set.Как неизменяемые объекты, namedtuple s являются хэшируемыми, а словари - нет.Вы также можете напрямую использовать набор понимания:

from collections import namedtuple

reading_type = namedtuple("reading_type", ["name", "value"])

{reading_type(rt.reading_type, rt.reading_type_id) 
    for unit in item.units
    for rt in unit.reading_types}
0 голосов
/ 18 декабря 2018

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

set([repr(val) for val in [...]])
...