Вопрос-Ответ

Get unique values from a list in python [duplicate]

Получение уникальных значений из списка в python

Я хочу получить уникальные значения из следующего списка:

['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']

Вывод, который мне требуется, это:

['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

Этот код работает:

output = []
for x in trends:
if x not in output:
output.append(x)
print(output)

есть ли лучшее решение, которое я должен использовать?

Переведено автоматически
Ответ 1

Сначала правильно объявите свой список, разделяя его запятыми. Вы можете получить уникальные значения, преобразовав список в набор.

mylist = ['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']
myset = set(mylist)
print(myset)

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

mynewlist = list(myset)

Другой возможностью, вероятно, более быстрой, было бы использовать set с самого начала вместо list . Тогда ваш код должен быть:

output = set()
for x in trends:
output.add(x)
print(output)

Как уже указывалось, наборы не сохраняют исходный порядок. Если вам это нужно, вам следует поискать реализацию ordered set (подробнее см. Этот вопрос).

Ответ 2

Чтобы соответствовать типу, который я бы использовал:

mylist = list(set(mylist))
Ответ 3

Если нам нужно сохранить порядок элементов, как насчет этого:

used = set()
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for x in mylist if x not in used and (used.add(x) or True)]

И еще одно решение с использованием reduce временного used параметра и без него.

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])

ОБНОВЛЕНИЕ - декабрь 2020 г. - Возможно, лучший подход!

Начиная с python 3.7, стандартный dict сохраняет порядок вставки.


Изменено в версии 3.7: порядок словаря гарантированно соответствует порядку вставки. Такое поведение было деталью реализации CPython из версии 3.6.


Таким образом, это дает нам возможность использовать dict.fromkeys() для устранения дублирования!

ПРИМЕЧАНИЕ: Спасибо @rlat за то, что предоставили нам этот подход в комментариях!

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = list(dict.fromkeys(mylist))

С точки зрения скорости - для меня это достаточно быстрый и читабельный подход, который стал моим новым любимым подходом!

ОБНОВЛЕНИЕ - март 2019 г.

И третье решение, которое является аккуратным, но немного медленным, поскольку .index равно O (n).

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for i, x in enumerate(mylist) if i == mylist.index(x)]

ОБНОВЛЕНИЕ - октябрь 2016 г.

Еще одно решение с reduce, но на этот раз без .append, которое делает его более удобочитаемым для человека и более понятным.

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])
#which can also be writed as:
unique = reduce(lambda l, x: l if x in l else l+[x], mylist, [])

ПРИМЕЧАНИЕ: Имейте в виду, что чем более удобочитаемым мы становимся, тем более неэффективным становится скрипт. За исключением только dict.fromkeys() подхода, специфичного для python 3.7+.

import timeit

setup = "mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']"

#10x to Michael for pointing out that we can get faster with set()
timeit.timeit('[x for x in mylist if x not in used and (used.add(x) or True)]', setup='used = set();'+setup)
0.2029558869980974

timeit.timeit('[x for x in mylist if x not in used and (used.append(x) or True)]', setup='used = [];'+setup)
0.28999493700030143

# 10x to rlat for suggesting this approach!
timeit.timeit('list(dict.fromkeys(mylist))', setup=setup)
0.31227896199925453

timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup='from functools import reduce;'+setup)
0.7149233570016804

timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup='from functools import reduce;'+setup)
0.7379565160008497

timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup='from functools import reduce;'+setup)
0.7400134069976048

timeit.timeit('[x for i, x in enumerate(mylist) if i == mylist.index(x)]', setup=setup)
0.9154880290006986

ОТВЕТЫ НА КОММЕНТАРИИ

Потому что @monica задала хороший вопрос о том, "как это работает?". Для всех, у кого возникли проблемы с пониманием этого. Я постараюсь дать более глубокое объяснение о том, как это работает и какое волшебство здесь происходит ;)

Итак, она сначала спросила:


Я пытаюсь понять, почему unique = [used.append(x) for x in mylist if x not in used] не работает.


Ну, это действительно работает

>>> used = []
>>> mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
>>> unique = [used.append(x) for x in mylist if x not in used]
>>> print used
[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']
>>> print unique
[None, None, None, None, None]

Проблема в том, что мы просто не получаем желаемых результатов внутри unique переменной, а только внутри used переменной. Это происходит потому, что во время понимания списка .append изменяет used переменную и возвращает None.

Итак, чтобы получить результаты в unique переменной и при этом использовать ту же логику с .append(x) if x not in used, нам нужно переместить этот .append вызов в правую часть списка понимания и просто вернуть x в левую часть.

Но если мы слишком наивны и просто используем:

>>> unique = [x for x in mylist if x not in used and used.append(x)]
>>> print unique
[]

Мы ничего не получим взамен.

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

x not in used and None

В принципе, это всегда:


  1. вычисляется как False когда x находится в used,

  2. вычисляется как None когда x отсутствует в used.

И в обоих случаях (False/None) это будет обработано как falsy значение, и в результате мы получим пустой список.

Но почему это оценивается как None когда x нет в used? Кто-то может спросить.

Ну, это потому, что именно так работают операторы короткого замыкания в Python.


Выражение x and y сначала вычисляет x; если x равно false, возвращается его значение; в противном случае вычисляется y и возвращается результирующее значение.


Поэтому, когда x не используется (т.Е. Когда его True) будет вычислена следующая часть или выражение (used.append(x)) и будет возвращено его значение (None).

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

Итак, мы действительно хотим оценивать used.append(x) только тогда, когда x нет в used, может быть, если есть способ превратить это None значение в truthy единицу, у нас все будет хорошо, верно?

Ну, да, и вот тут в игру вступают операторы 2-го типа short-circuit.


Выражение x or y сначала вычисляет x; если x равно true, возвращается его значение; в противном случае вычисляется y и возвращается результирующее значение.


Мы знаем, что это .append(x) будет всегда falsy, поэтому, если мы просто добавим одно or рядом с ним, мы всегда получим следующую часть. Вот почему мы пишем:

x not in used and (used.append(x) or True)

таким образом, мы можем вычислять used.append(x) и получать True в результате, только когда первая часть выражения (x not in used) является True.

Аналогичный способ можно увидеть во 2-м подходе с reduce методом.

(l.append(x) or l) if x not in l else l
#similar as the above, but maybe more readable
#we return l unchanged when x is in l
#we append x to l and return l when x is not in l
l if x in l else (l.append(x) or l)

где мы:


  1. Добавляйте x в l и возвращайте это значение, l когда x его нет в l. Благодаря or инструкции .append вычисляется и l возвращается после этого.

  2. Возвращает l нетронутыми, когда x находится в l

Ответ 4

Список на Python:

>>> a = ['a', 'b', 'c', 'd', 'b']

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

>>> b = set(a)
>>> print(b)
{'b', 'c', 'd', 'a'}
python list