Добавить только уникальные значения в список в python

Я пытаюсь изучить python. Вот соответствующая часть упражнения:

Для каждого слова, проверьте, нет ли слова в списке. Если слова нет в списке, добавьте его в список.

Вот что у меня есть.

fhand = open('romeo.txt')
output = []

for line in fhand:
    words = line.split()
    for word in words:
        if word is not output:
            output.append(word)

print sorted(output)

Вот что я получаю.

['Arise', 'But', 'It', 'Juliet', 'Who', 'already', 'and', 'and', 'and', 'breaks', 'east', 'envious', 'fair', 'grief', 'is', 'is', 'is', 'kill', 'light', 'moon', 'pale', 'sick', 'soft', 'sun', 'sun', 'the', 'the', 'the', 'through', 'what', 'window', 'with', 'yonder']

Примечание: дублирование (и, есть, солнце и т.д.).

Как получить только уникальные значения?

Ответ 1

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

myList = ['Arise', 'But', 'It', 'Juliet', 'Who', 'already', 'and', 'and', 'and', 
     'breaks', 'east', 'envious', 'fair', 'grief', 'is', 'is', 'is', 'kill', 'light', 
     'moon', 'pale', 'sick', 'soft', 'sun', 'sun', 'the', 'the', 'the', 
     'through', 'what', 'window', 'with', 'yonder']

auxiliaryList = []
for word in myList:
    if word not in auxiliaryList:
        auxiliaryList.append(word)

выход:

['Arise', 'But', 'It', 'Juliet', 'Who', 'already', 'and', 'breaks', 'east', 
  'envious', 'fair', 'grief', 'is', 'kill', 'light', 'moon', 'pale', 'sick',
  'soft', 'sun', 'the', 'through', 'what', 'window', 'with', 'yonder']

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


Используйте set() !, Набор представляет собой неупорядоченную коллекцию без повторяющихся элементов.
Основное использование включает тестирование членства и устранение дублирующих записей.

auxiliaryList = list(set(myList))

выход:

['and', 'envious', 'already', 'fair', 'is', 'through', 'pale', 'yonder', 
 'what', 'sun', 'Who', 'But', 'moon', 'window', 'sick', 'east', 'breaks', 
 'grief', 'with', 'light', 'It', 'Arise', 'kill', 'the', 'soft', 'Juliet']

Ответ 2

Вместо is not operator, вы должны использовать not in operator, чтобы проверить, есть ли элемент в списке:

if word not in output:

Кстати, использование set намного эффективнее (см. "Сложность времени"):

with open('romeo.txt') as fhand:
    output = set()
    for line in fhand:
        words = line.split()
        output.update(words)

ОБНОВЛЕНИЕ set не сохраняет первоначальный порядок. Чтобы сохранить порядок, используйте набор в качестве вспомогательной структуры данных:

output = []
seen = set()
with open('romeo.txt') as fhand:
    for line in fhand:
        words = line.split()
        for word in words:
            if word not in seen:  # faster than 'word not in output'
                seen.add(word)
                output.append(word)

Ответ 3

Здесь "однострочный", который использует эту реализацию для удаления дубликатов при сохранении порядка:

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

output = unique([word for line in fhand for word in line.split()])

Последняя строка выравнивает fhand в список слов, а затем вызывает unique() в результирующем списке.

Ответ 4

Один из способов - увидеть, есть ли он в списке до добавления, что и делает ответ Тони. Если вы хотите удалить повторяющиеся значения после создания списка, вы можете использовать set() чтобы преобразовать существующий список в набор уникальных значений, а затем использовать list() чтобы снова преобразовать его в список. Все в одной строке:

list(set(output))

Если вы хотите отсортировать по алфавиту, просто добавьте sorted() к приведенному выше. Вот результат:

['Arise', 'But', 'It', 'Juliet', 'Who', 'already', 'and', 'breaks', 'east', 'envious', 'fair', 'grief', 'is', 'kill', 'light', 'moon', 'pale', 'sick', 'soft', 'sun', 'the', 'through', 'what', 'window', 'with', 'yonder']