Подтвердить что ты не робот

Учет списка, проверьте, уникален ли элемент

Я пытаюсь написать инструкцию по пониманию списка, которая будет добавлять только элемент, если он не содержится в списке. Есть ли способ проверить текущие элементы в списке, который в настоящее время строится? Вот краткий пример:

Ввод

{
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

Выход

["running", "engineering", "dancing", "art", "theatre", "music"]

Код без использования понимания списка

output = []
for name, hobbies in input.items():
    for hobby in hobbies:
        if hobby not in output:
            output.append(hobby)

Моя попытка

[hobby for name, hobbies in input.items() for hobby in hobbies if hobby not in ???]
4b9b3361

Ответ 1

Вы можете использовать set и установить понимание:

{hobby for name, hobbies in input.items() for hobby in hobbies}

Как m.wasowski отметил, мы не используем name здесь, поэтому вместо item.values() можно использовать

{hobby for hobbies in input.values() for hobby in hobbies}

Если вам действительно нужен список в качестве результата, вы можете это сделать (но обратите внимание, что обычно вы можете работать с наборами без каких-либо проблем):

list({hobby for hobbies in input.values() for hobby in hobbies})

Ответ 2

Как этот ответ предлагает: вы можете использовать фильтр уникальности:

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

и вызовите с помощью:

>>> f7(hobby for name, hobbies in input.items() for hobby in hobbies)
['running', 'engineering', 'dancing', 'art', 'theatre', 'music']

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

Еще одно преимущество - как написано в связанном ответе - сохранение порядка элементов. Для некоторых приложений это может быть необходимо.

Ответ 3

наборы и словари - ваши друзья здесь:

from collections import OrderedDict
from itertools import chain # 'flattens' collection of iterables

data = {
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

# using set is the easiest way, but sets are unordered:
print {hobby for hobby in chain.from_iterable(data.values())}
# output:
# set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])


# or use OrderedDict if you care about ordering:
print OrderedDict(
        (hobby, None) for hobby in chain.from_iterable(data.values())
    ).keys()
# output:
# ['dancing', 'art', 'theatre', 'running', 'engineering', 'music']

Ответ 4

Если вам действительно нужен listcomp и только list-comp, вы можете сделать

>>> s = []
>>> [s.append(j)  for i in d.values() for j in i if j not in s]
[None, None, None, None, None, None]
>>> s
['dancing', 'art', 'theatre', 'running', 'engineering', 'music']

Здесь s является результатом побочного эффекта, а d - ваш исходный словарь. Единственное преимущество здесь в том, что вы можете сохранить порядок в отличие от большинства других ответов здесь.

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

Ответ 5

Существует еще один способ написать это, что немного более подробно описывает то, что вы на самом деле делаете, и не требует вложенного (двойного for) понимания:

output = set.union(*[set(hobbies) for hobbies in input_.values()])

Это станет еще приятнее, если вы представите ввод более концептуально здоровым, т.е. используйте наборы для хобби каждого человека (так как там не должно быть повторений):

input_ = {
    "Stefan" : {"running", "engineering", "dancing"},
    "Bob" : {"dancing", "art", "theatre"}, 
    "Julia" : {"running", "music", "art"}
}

output = set.union(*input_.values())

Ответ 6

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

list(set(sum(hobbies_dict.values(), [])))

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

from operator import or_
from functools import reduce # Allowed, but unnecessary in Python 2.x
list(reduce(or_, map(set, hobbies_dict.values())))

Или (непреднамеренный каламбур, я клянусь), вместо использования побитового или оператора просто используйте set.union и передайте ему распакованное заданное отображение ваших значений. Нет необходимости импортировать or_ и reduce! Эта идея вдохновлена ​​ответом Thijs van Dien.

list(set.union(*map(set, hobbies_dict.values())))

Ответ 7

Используйте набор:

dict = {
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

myset = set()
for _, value in dict.items():
    for item in value:
        myset.add(item)

print(myset)

Ответ 8

Как насчет этого:

set(dict['Bob']+dict['Stefan']+dict['Julia'])
>>> set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])

Или более красиво:

dict = {
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

list_ = []
for y in dict.keys():
    list_ = list_ + dict[y]
list_ = set(list_)
>>> list_
set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])

вы можете применить функцию list к списку_, например list(list_), чтобы вернуть список, а не набор.