Получать уникальные значения из списка в 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)

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

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

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

Ответ 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 var.

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, [])

ОБНОВЛЕНИЕ - март 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, [])

ПРИМЕЧАНИЕ: Имейте в виду, что чем более понятным мы становимся, тем более нестабильным является сценарий.

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.4188511371612549

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

timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup=setup)
1.8778090476989746

timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup=setup)
2.13108491897583

timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup=setup)
2.207760810852051

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

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

Потому что @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 операторы короткого замыкания operators works.

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

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

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

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

Что ж, да, и вот тут начинают играть операторы второго типа short-circuit.

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

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

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

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

Подобный способ можно увидеть во втором подходе с методом 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 устанавливает то, что вам нужно. Объявите вывод следующим образом:

output = set()  # initialize an empty set

и вы готовы добавить элементы с помощью output.add(elem) и убедиться, что они уникальны.

Предупреждение: наборы НЕ сохраняют первоначальный порядок списка.

Ответ 5

Список Python:

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

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

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

Ответ 6

Поддержание порядка:

# oneliners
# slow -> . --- 14.417 seconds ---
[x for i, x in enumerate(array) if x not in array[0:i]]

# fast -> . --- 0.0378 seconds ---
[x for i, x in enumerate(array) if array.index(x) == i]

# multiple lines
# fastest -> --- 0.012 seconds ---
uniq = []
[uniq.append(x) for x in array if x not in uniq]
uniq

Заказ не имеет значения:

# fastest-est -> --- 0.0035 seconds ---
list(set(array))

Ответ 7

Это просто solution-

list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
list=set(list)

Ответ 8

Получение уникальных элементов из списка

mylist = [1,2,3,4,5,6,6,7,7,8,8,9,9,10]

Использование простой логики из наборов - наборы представляют собой уникальный список элементов

mylist=list(set(mylist))

In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Использование простой логики

newList=[]
for i in mylist:
    if i not in newList:
        newList.append(i)

In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Использование метода pop → pop удаляет последний или проиндексированный элемент и отображает его пользователю. видео

k=0
while k < len(mylist):
    if mylist[k] in mylist[k+1:]:
        mylist.pop(mylist[k])
    else:
        k=k+1

In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Используя Numpy

import numpy as np
np.unique(mylist)

In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Ссылка

Ответ 9

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

list(set(my_not_unique_list))

Просто и коротко.

Ответ 10

Если вы используете numpy в своем коде (который может быть хорошим выбором для больших объемов данных), посмотрите numpy.unique:

>>> import numpy as np
>>> wordsList = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
>>> np.unique(wordsList)
array([u'PBS', u'debate', u'job', u'nowplaying', u'thenandnow'], 
      dtype='<U10')

(http://docs.scipy.org/doc/numpy/reference/generated/numpy.unique.html)

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

>>> for word in np.unique(wordsList):
...     print word
... 
PBS
debate
job
nowplaying
thenandnow

Если вы действительно хотите вернуть список vanilla python, вы всегда можете вызвать list().

Однако результат автоматически сортируется, как вы можете видеть из приведенных выше фрагментов кода. Проверьте numy unique без сортировки, если требуется сохранение порядка списка.

Ответ 11

Вот краткое описание получения неупорядоченных или упорядоченных уникальных элементов.

Учитывая

from collections import OrderedDict


seq = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']

код

# Unordered
list(set(seq))
# Out: ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying']

# Order-preserving
list(OrderedDict.fromkeys(seq))
# Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

В качестве альтернативы в Python 3. 6+:

# Order-preserving
list(dict.fromkeys(seq))
# Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

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

Ответ 12

Такой же уникальный список заказов, используя только сжатие списка.

> my_list = [1, 2, 1, 3, 2, 4, 3, 5, 4, 3, 2, 3, 1]
> unique_list = [
>    e
>    for i, e in enumerate(my_list)
>    if my_list.index(e) == i
> ]
> unique_list
[1, 2, 3, 4, 5]

enumerates дает индекс i и элемент e как tuple.

my_list.index возвращает первый индекс e. Если первый индекс не является i, то текущая итерация e не является первой e в списке.

Edit

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

Ответ 13

Используя базовое свойство словаря Python:

inp=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
d={i for i in inp}
print d

Выход будет:

set([u'nowplaying', u'job', u'debate', u'PBS', u'thenandnow'])

Ответ 14

Во-первых, приведенный вами пример не является допустимым списком.

example_list = [u'nowplaying',u'PBS', u'PBS', u'nowplaying', u'job', u'debate',u'thenandnow']

Предположим, что выше приведен пример списка. Затем вы можете использовать следующий рецепт, чтобы предоставить пример документа itertools, который может возвращать уникальные значения и сохранять порядок, как вам кажется. Итерируемым здесь является example_list

from itertools import ifilterfalse

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in ifilterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

Ответ 15

def get_distinct(original_list):
    distinct_list = []
    for each in original_list:
        if each not in distinct_list:
            distinct_list.append(each)
    return distinct_list

Ответ 16

set может помочь вам отфильтровать элементы из списка, которые являются дубликатами. Это будет хорошо работать для элементов str, int или tuple, но если ваш список содержит dict или другие элементы list, то в итоге вы получите исключения TypeError.

Вот общее решение по сохранению порядка для обработки некоторых (не всех) типов без хэширования:

def unique_elements(iterable):
    seen = set()
    result = []
    for element in iterable:
        hashed = element
        if isinstance(element, dict):
            hashed = tuple(sorted(element.iteritems()))
        elif isinstance(element, list):
            hashed = tuple(element)
        if hashed not in seen:
            result.append(element)
            seen.add(hashed)
    return result

Ответ 17

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

from collections import Counter
l = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
c = Counter(l)

Ответ 18

Чтобы получить уникальные значения из вашего, используйте следующий код:

trends = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
output = set(trends)
output = list(output)

ВАЖНО: Подход выше не будет работать, если какой-либо из элементов в списке не hashable, который относится к случаю mutable, например list или dict.

trends = [{'super':u'nowplaying'}, u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
output = set(trends)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: unhashable type: 'dict'

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

from copy import deepcopy

try:
    trends = [{'super':u'nowplaying'}, [u'PBS',], [u'PBS',], u'nowplaying', u'job', u'debate', u'thenandnow', {'super':u'nowplaying'}]
    output = set(trends)
    output = list(output)
except TypeError:
    trends_copy = deepcopy(trends)
    while trends_copy:
        trend = trends_copy.pop()
        if trends_copy.count(trend) == 0:
            output.append(trend)
print output

Ответ 19

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

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenadnow']
mylist = [i for i in set(mylist)]

вывод будет

[u'nowplaying', u'job', u'debate', u'PBS', u'thenadnow']

хотя порядок не будет сохранен.

Другим более простым ответом может быть (без использования наборов)

>>> t = [v for i,v in enumerate(mylist) if mylist.index(v) == i]
[u'nowplaying', u'PBS', u'job', u'debate', u'thenadnow']

Ответ 20

def setlist(lst=[]):
   return list(set(lst))

Ответ 21

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

def unique(sequence):
    """Generate unique items from sequence in the order of first occurrence."""
    seen = set()
    for value in sequence:
        if value in seen:
            continue

        seen.add(value)

        yield value

Он будет генерировать значения, чтобы он работал с более чем списками, например. unique(range(10)). Чтобы получить список, просто вызовите list(unique(sequence)), например:

>>> list(unique([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))
[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']

У этого есть требование, чтобы каждый элемент был хешируемым, а не только сопоставимым, но большинство вещей в Python есть, и это O (n), а не O (n ^ 2), поэтому будет отлично работать с длинным списком.

Ответ 22

Вы можете использовать наборы. Чтобы быть ясным, я объясняю, в чем разница между списком и набором. множеств - это неупорядоченный набор уникальных элементов. Список представляет собой упорядоченный набор элементов. Таким образом,

    unicode_list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job',u'debate', u'thenandnow']
    list_unique=list(set(unicode_list))
    print list_unique
[u'nowplaying', u'job', u'debate', u'PBS', u'thenandnow']

Но: Не используйте list/set при именовании переменных. Это вызовет ошибку: EX: Вместо списка использования вместо unicode_list в приведенном выше.

list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job',u'debate', u'thenandnow']
        list_unique=list(set(list))
        print list_unique
    list_unique=list(set(list))
TypeError: 'list' object is not callable

Ответ 23

  • В начале вашего кода просто объявляйте свой выходной список пустым: output=[]
  • Вместо кода вы можете использовать этот код trends=list(set(trends))

Ответ 24

Набор представляет собой коллекцию неупорядоченных и уникальных элементов. Таким образом, вы можете использовать set, как показано ниже, чтобы получить уникальный список:

unique_list = list(set([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))

Ответ 25

Мое решение проверить содержимое для уникальности, но сохранить исходный порядок:

def getUnique(self):
    notunique = self.readLines()
    unique = []
    for line in notunique: # Loop over content
        append = True # Will be set to false if line matches existing line
        for existing in unique:
            if line == existing: # Line exists ? do not append and go to the next line
                append = False
                break # Already know file is unique, break loop
        if append: unique.append(line) # Line not found? add to list
    return unique

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

Ответ 26

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

from collections import OrderedDict

def keep_unique(elements):
    return list(OrderedDict.fromkeys(elements).keys())

elements = [2, 1, 4, 2, 1, 1, 5, 3, 1, 1]
required_output = [2, 1, 4, 5, 3]

assert keep_unique(elements) == required_output

Фактически, если вы используете Python ≥ 3.6, для этого можно использовать plain dict:

def keep_unique(elements):
    return list(dict.fromkeys(elements).keys())

Это стало возможным после введения "компактного" представления dicts. Проверьте здесь. Хотя это "рассмотрело деталь реализации и не следует полагаться".

Ответ 27

используйте set для удаления дубликата списка и возврата в список

def get_unique_list(lst):
        if isinstance(lst,list):
            return list(set(lst))

Ответ 28

Я знаю, что это старый вопрос, но вот мое уникальное решение: class inheritance!:

class UniqueList(list):
    def appendunique(self,item):
        if item not in self:
            self.append(item)
            return True
        return False

Затем, если вы хотите уникально добавить элементы в список, вы просто вызываете appendunique в UniqueList. Поскольку он наследуется от списка, он в основном действует как список, поэтому вы можете использовать такие функции, как index() и т.д. И поскольку он возвращает true или false, вы можете узнать, было ли успешное добавление (уникальный элемент) или сбой (уже в список).

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

Пример кода использования:

unique = UniqueList()

for each in [1,2,2,3,3,4]:
    if unique.appendunique(each):
        print 'Uniquely appended ' + str(each)
    else:
        print 'Already contains ' + str(each)

Печать

Uniquely appended 1
Uniquely appended 2
Already contains 2
Uniquely appended 3
Already contains 3
Uniquely appended 4

Копирование в список:

unique = UniqueList()

for each in [1,2,2,3,3,4]:
    unique.appendunique(each)

newlist = unique[:]
print newlist

Печать

[1, 2, 3, 4]

Ответ 29

Для длинных массивов

s = np.empty(len(var))

s[:] = np.nan

for  x in  set(var):

    x_positions = np.where(var==x)

    s[x_positions[0][0]]=x


sorted_var=s[~np.isnan(s)]

Ответ 30

Попробуйте эту функцию, она похожа на ваш код, но это динамический диапазон.

def unique(a):

    k=0
    while k < len(a):
        if a[k] in a[k+1:]:
            a.pop(k)
        else:
            k=k+1



    return a