从python中的列表中获取唯一值

sav*_*tha 701 python

我想从以下列表中获取唯一值:

['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']
Run Code Online (Sandbox Code Playgroud)

我需要的输出是:

['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
Run Code Online (Sandbox Code Playgroud)

此代码有效:

output = []
for x in trends:
    if x not in output:
        output.append(x)
print(output)
Run Code Online (Sandbox Code Playgroud)

我应该使用更好的解决方案吗?

lef*_*rav 913

首先正确声明您的列表,用逗号分隔.您可以通过将列表转换为集合来获取唯一值.

mylist = ['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']
myset = set(mylist)
print(myset)
Run Code Online (Sandbox Code Playgroud)

如果您进一步将其用作列表,则应通过执行以下操作将其转换回列表:

mynewlist = list(myset)
Run Code Online (Sandbox Code Playgroud)

另一种可能性,可能更快,就是从头开始使用一个集合,而不是列表.那你的代码应该是:

output = set()
for x in trends:
    output.add(x)
print(output)
Run Code Online (Sandbox Code Playgroud)

正如已经指出的那样,集合不保持原始顺序.如果您需要,您应该查看有序集.

  • "append"意味着添加到最后,这对于列表是准确且有意义的,但是set没有排序的概念,因此没有开头或结尾,所以"add"对他们更有意义. (31认同)
  • 如果您需要维护设置顺序,PyPI上还有一个库:https://pypi.python.org/pypi/ordered-set (4认同)
  • 为什么列表'.append'和集合有'.add'? (4认同)
  • 'sets'模块已被弃用,是的.因此,您无需"导入集"即可获得该功能.如果你看到`import sets; 不推荐使用内置的'set'类https://docs.python.org/2/library/stdtypes.html#set (2认同)
  • 如果列表的值不可散列(例如,集合或列表),则此方法不起作用 (2认同)

ale*_*mol 294

为了与我使用的类型保持一致:

mylist = list(set(mylist))
Run Code Online (Sandbox Code Playgroud)

  • 请注意,结果将是无序的. (77认同)
  • @Ninjakannon您的代码将按字母顺序对列表进行排序.这不一定是原始列表的顺序. (40认同)
  • 请注意,在python 3中执行此操作的一种巧妙方法是`mylist = [*{*mylist}]`.这是一个`*arg`风格的set-expansion,然后是`*arg`风格的列表扩展. (11认同)
  • 注意:如果列表具有不可散列的元素(例如,元素本身就是集合、列表或散列),则此操作会失败。 (5认同)
  • @LukeDavis 对我来说最好的答案,`sorted([*{*c}])` 比 `sorted(list(set(c)))` 快 25%(用 `timeit.repeat` 测量,数字=100000) (3认同)

Tod*_*dor 88

如果我们需要保持元素顺序,那么这个怎么样:

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)]
Run Code Online (Sandbox Code Playgroud)

还有一个使用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, [])
Run Code Online (Sandbox Code Playgroud)

更新 - 2016年10月1日

另一个解决方案.index,但这次没有reduce它使它更易于阅读和理解.

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)]
Run Code Online (Sandbox Code Playgroud)

注意:请记住,我们得到的人类可读性更高,脚本更难以理解.

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, [])
Run Code Online (Sandbox Code Playgroud)

回答评论

因为@monica问了一个关于"这怎么工作?"的好问题.对于每个有问题的人来说.我将尝试更深入地解释这是如何工作的以及这里发生的巫术;)

所以她先问:

我试着理解为什么.append不起作用.

嗯,它实际上工作

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
Run Code Online (Sandbox Code Playgroud)

问题是我们只是没有在unique = [used.append(x) for x in mylist if x not in used]变量中获得所需的结果,而只是在unique变量内部.这是因为在列表理解期间used修改.append变量并返回used.

因此,为了将结果输入None变量,并且仍然使用相同的逻辑unique,我们需要.append(x) if x not in used在列表推导的右侧移动此调用,然后返回.append左侧.

但是,如果我们太天真,只需要:

>>> 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]
Run Code Online (Sandbox Code Playgroud)

我们什么也得不到回报.

同样,这是因为该x方法返回.append,并且这给我们的逻辑表达式提供了以下外观:

>>> unique = [x for x in mylist if x not in used and used.append(x)]
>>> print unique
[]
Run Code Online (Sandbox Code Playgroud)

这基本上总是:

  1. 评估None何时False进入x,
  2. 评估used何时None不在x.

在两种情况下(used/ False),这将被视为None值,我们将得到一个空列表作为结果.

但为什么这个评估falsy时间None不在x?有人可能会问.

嗯,这是因为这就是Python的短路运营商的工作方式.

表达式used首先评估x; 如果x为false,则返回其值; 否则,将评估y并返回结果值.

因此,当x and y未使用时(即,当它x)时,下一部分或表达式将被计算(True)并且将返回其值(used.append(x)).

但这就是我们想要的,以便从列表中获取具有重复项的独特元素,我们希望None它们只有在我们遇到的时候才会进入新列表.

所以我们真的只想.appendused.append(x)不在的时候进行评估x,也许如果有办法将这个used值变成None一个我们会好的,对吗?

嗯,是的,这里是第二类truthy运营商发挥作用的地方.

表达式short-circuit首先评估x; 如果x为真,则返回其值; 否则,将评估y并返回结果值.

我们知道x or y永远都是.append(x),所以如果我们只是falsy在他旁边添加一个,我们将永远得到下一部分.这就是为什么我们写:

x not in used and None
Run Code Online (Sandbox Code Playgroud)

所以我们可以评估 or并得到used.append(x)结果,只有表达式的第一部分True(x not in used).

在第二种方法中可以看到类似的True方式.

x not in used and (used.append(x) or True)
Run Code Online (Sandbox Code Playgroud)

在哪里我们:

  1. 追加reducex并返回llx.感谢l语句or被评估并.append在此之后返回.
  2. 返回l时,不变lx

  • 自 Python 3.7 以来,另一个值得一提且有效的选项是使用“dict”,因为它保留键的顺序,但也消除了重复项:“list(dict.fromkeys(mylist))”从时间角度来看,它排名第三。 (4认同)
  • @Monica 基本上,因为 `used.append(x)` 将 `x` 添加到 `used` 中,但是这个函数的返回值是 `None`,所以如果我们跳过 `or True` 部分,我们得到:`x not in used 和 None 总是会评估为 False 并且唯一的列表将保持为空。 (2认同)
  • 别担心,没有愚蠢的问题,只有愚蠢的答案:)我更新了我的答案,试图更好地解释它是如何工作的,希望我说清楚,你现在可以理解它. (2认同)

Sam*_*zzo 86

你的输出变量是什么类型的?

Python 是您所需要的.声明输出如下:

output = set()  # initialize an empty set
Run Code Online (Sandbox Code Playgroud)

你准备好添加元素,output.add(elem)并确保它们是独一无二的.

警告:设置不保留列表的原始顺序.


Nic*_*bey 77

您提供的示例与Python中的列表不对应.它类似于嵌套的字典,可能不是你想要的.

Python列表:

>>> a = ['a', 'b', 'c', 'd', 'b']
Run Code Online (Sandbox Code Playgroud)

要获取唯一项目,只需将其转换为一个集合(如果需要,您可以将其转换回列表):

>>> b = set(a)
>>> print(b)
{'b', 'c', 'd', 'a'}
Run Code Online (Sandbox Code Playgroud)

  • 很好,所以`a = list(set(a))`获取唯一的项目. (49认同)
  • Brian,`set(a)`足以"获得独特的物品".如果由于某种原因特别需要列表,则只需构建另一个列表. (9认同)
  • 请注意,结果将是无序的. (4认同)

dai*_*no3 41

维持秩序:

# 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
Run Code Online (Sandbox Code Playgroud)

订单无关紧要:

# fastest-est -> --- 0.0035 seconds ---
list(set(array))
Run Code Online (Sandbox Code Playgroud)

  • 这对于您想要保持顺序且不关心速度的简单脚本非常有用。 (2认同)
  • 我真的很感谢你抽出时间来打破时间戳 (2认同)

pyl*_*ang 19

删除重复项的选项可能包括以下通用数据结构:

这是关于快速使用Python之一的摘要。

给定

from collections import OrderedDict


seq = [u"nowplaying", u"PBS", u"PBS", u"nowplaying", u"job", u"debate", u"thenandnow"]
Run Code Online (Sandbox Code Playgroud)

选项1-一组(无序):

list(set(seq))
# ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying']
Run Code Online (Sandbox Code Playgroud)

选项2 -Python没有排序集,但是这里有一些模仿一个(插入排序)的方法:

list(OrderedDict.fromkeys(seq))
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
Run Code Online (Sandbox Code Playgroud)

list(dict.fromkeys(seq))                               # py36
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
Run Code Online (Sandbox Code Playgroud)

如果使用Python 3.6+,建议使用最后一个选项。

注意:列出的元素必须是可哈希的。请参阅此博客文章中有关后一个示例的详细信息。此外,请参见R. Hettinger 关于相同技术的文章。保留顺序字典是他早期实现之一。另请参见有关总订购的更多信息。

  • @Henry Henrinson 我很感激你表达了你对这个答案投反对票的理由。但是,您的意见和声明“Python 3.6 解决方案不保留顺序”不符合参考条件。需要明确的是,在 Python 3.6 中,字典 [保留 *插入顺序*](/sf/answers/2798652111/) 在 CPython 实现中。它是 Python 3.7+ 中的一个语言特性。此外,请参阅有关当时声称的该方法的正在进行的 [博客文章](https://www.peterbe.com/plog/fastest-way-to-uniquify-a-list-in-python-3.6)成为 Python 3.6 中最快的有序选项。 (3认同)

s_m*_*_mj 19

从列表中获取独特元素

mylist = [1,2,3,4,5,6,6,7,7,8,8,9,9,10]
Run Code Online (Sandbox Code Playgroud)

使用集合中的简单逻辑 - 集合是唯一的项目列表

mylist=list(set(mylist))

In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Run Code Online (Sandbox Code Playgroud)

使用简单逻辑

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]
Run Code Online (Sandbox Code Playgroud)

使用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]
Run Code Online (Sandbox Code Playgroud)

使用Numpy

import numpy as np
np.unique(mylist)

In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Run Code Online (Sandbox Code Playgroud)

参考


Mul*_*mer 16

set - 无序的独特元素集合.元素列表可以传递给set的构造函数.因此,传递具有重复元素的列表,我们使用唯一元素进行设置并将其转换回列表然后获取具有唯一元素的列表.我不能说性能和内存开销,但我希望,对于小型列表来说并不是那么重要.

list(set(my_not_unique_list))
Run Code Online (Sandbox Code Playgroud)

简单而简短.


小智 15

如果你在代码中使用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')
Run Code Online (Sandbox Code Playgroud)

(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
Run Code Online (Sandbox Code Playgroud)

如果你真的想要一个vanilla python列表,你可以随时调用list().

但是,结果会自动排序,您可以从上面的代码片段中看到.如果需要保留列表顺序,请检查numpy unique而不排序.


Odr*_*ded 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]
Run Code Online (Sandbox Code Playgroud)

enumerates给索引i和元素e一个tuple.

my_list.index返回第一个索引e.如果第一个索引不是,i则当前迭代e不是e列表中的第一个.

编辑

我应该注意,这不是一个很好的方法,在性能方面.这只是一种仅使用列表压缩来实现它的方法.


SOU*_*HIT 7

通过使用Python Dictionary的基本属性:

inp=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
d={i for i in inp}
print d
Run Code Online (Sandbox Code Playgroud)

输出将是:

set([u'nowplaying', u'job', u'debate', u'PBS', u'thenandnow'])
Run Code Online (Sandbox Code Playgroud)

  • 这是一个“集合”,而不是一个“ dict”。 (3认同)

Sen*_*ran 6

首先,您提供的示例不是有效列表.

example_list = [u'nowplaying',u'PBS', u'PBS', u'nowplaying', u'job', u'debate',u'thenandnow']
Run Code Online (Sandbox Code Playgroud)

假设上面是示例列表.然后,您可以使用以下配方作为itertools示例文档,该文档可以返回唯一值并保留您看起来需要的顺序.这里的iterable是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
Run Code Online (Sandbox Code Playgroud)


小智 6

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
Run Code Online (Sandbox Code Playgroud)

  • 请添加一些解释 - 这只是代码.如果你看看其他答案,他们总是使用代码_和_解释. (6认同)

Rég*_* B. 6

set可以帮助您筛选出重复列表中的元素.这将很好的工作str,inttuple元素,但如果你的列表中包含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
Run Code Online (Sandbox Code Playgroud)


Ber*_*pac 5

作为奖励,Counter是获取每个值的唯一值和计数的简单方法:

from collections import Counter
l = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
c = Counter(l)
Run Code Online (Sandbox Code Playgroud)


sko*_*kin 5

如果你想从列表中获取唯一元素并保持其原始顺序,那么你可以使用OrderedDictPython 标准库中的数据结构:

\n\n
from collections import OrderedDict\n\ndef keep_unique(elements):\n    return list(OrderedDict.fromkeys(elements).keys())\n\nelements = [2, 1, 4, 2, 1, 1, 5, 3, 1, 1]\nrequired_output = [2, 1, 4, 5, 3]\n\nassert keep_unique(elements) == required_output\n
Run Code Online (Sandbox Code Playgroud)\n\n

事实上,如果您使用的是 Python \xe2\x89\xa5 3.6,则可以使用 plaindict来实现:

\n\n
def keep_unique(elements):\n    return list(dict.fromkeys(elements).keys())\n
Run Code Online (Sandbox Code Playgroud)\n\n

在引入字典的“紧凑”表示之后,这成为可能。在这里查看一下。尽管这“被认为是实施细节,不应依赖”。

\n


归档时间:

查看次数:

1376537 次

最近记录:

6 年,1 月 前