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

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

вход

{ "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 ???] 

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

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

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

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

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

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

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

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

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

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

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

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

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

     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()) 

    Если вам действительно нужен listcomp и только список-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, а результат – побочный эффект. Не делайте это как практику. Этот ответ – просто показать вам, что вы можете добиться этого, используя только один список

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

     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 ! Эта идея вдохновлена ответом Тийса ван Диена .

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

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

     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) 

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

     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_ like list(list_) чтобы вернуть список, а не набор.