繁体   English   中英

从python中的列表中获取唯一值[重复]

[英]Get unique values from a list in python [duplicate]

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

['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)

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

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

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)

正如已经指出的那样,集合不保持原始顺序。 如果需要,您应该寻找有序集实现(有关更多信息,请参阅此问题)。

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

mylist = list(set(mylist))

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

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

更新 - 2020 年 12 月 - 也许是最好的方法!

从 python 3.7 开始,标准dict保留插入顺序。

在 3.7 版更改: 字典顺序保证是插入顺序。 此行为是 3.6 中 CPython 的实现细节。

所以这使我们能够使用dict.from_keys进行重复数据删除!

注意:感谢@rlat在评论中为我们提供了这种方法!

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

在速度方面 - 对我来说它足够快和足够可读,成为我最喜欢的方法!

更新 - 2019 年 3 月

还有第三个解决方案,这是一个简洁的解决方案,但有点慢,因为.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 年 10 月

另一个带有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, [])

注意:请记住,我们获得的人类可读性越高,脚本的性能就越差。 除了特定于 python 3.7+ 的dict.from_keys方法。

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) if x not in used相同的逻辑,我们需要将这个.append调用移动到列表.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. used x时计算结果为False
  2. xused时计算为None

在这两种情况下( False / None ),这将被视为falsy值,因此我们将得到一个空列表。

但是为什么当x没有used时它的计算结果是None呢? 有人可能会问。

嗯,这是因为 Python 的短路运算符就是这样工作的

表达式x and y首先计算 x; 如果 x 为假,则返回其值; 否则,计算 y 并返回结果值。

因此,当x未被使用时(即当它的True下一部分或表达式将被评估used.append(x)并且它的值None将被返回。

但这就是我们想要从具有重复项的列表中获取唯一元素的目的,我们希望仅当我们第一次遇到它们时才将它们.append到新列表中。

所以我们真的想只在x不在used时评估used.append(x) ,也许如果有办法把这个None值变成一个truthy值,我们会没事的,对吧?

嗯,是的,这里是第二种类型的short-circuit算子发挥作用的地方。

表达式x or y首先计算 x; 如果 x 为真,则返回其值; 否则,计算 y 并返回结果值。

我们知道.append(x)永远是falsy ,所以如果我们只是在他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并在x不在l时返回l 多亏了or语句, .append被评估并在此之后返回l
  2. xl时返回l不变

一个 Python 列表:

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

要获得独特的物品,只需将其转换为一个集合(如果需要,您可以再次将其转换回列表):

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

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

Python正是您所需要的。 像这样声明输出:

output = set()  # initialize an empty set

并且您已准备好使用output.add(elem)添加元素并确保它们是唯一的。

警告:集合不保留列表的原始顺序。

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

  • set : 无序、唯一的元素
  • 有序集:有序的、唯一的元素

以下是有关在 Python 中快速获取其中任何一个的摘要。

给定的

from collections import OrderedDict


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

代码

选项 1 - 一组(无序):

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

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

list(OrderedDict.fromkeys(seq))
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

list(dict.fromkeys(seq))                               # py36
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

如果使用 Python 3.6+,建议使用最后一个选项。 在这篇文章中查看更多详细信息。

注意:列出的元素必须是hashable 请参阅此博客文章中有关后一个示例的详细信息。 此外,请参阅 R. Hettinger 关于相同技术的帖子 保留顺序的 dict 是从他的早期实现之一扩展而来的。 另请参阅有关总排序的更多信息。

维持秩序:

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

这是简单的解决方案 -

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

从 List 中获取唯一元素

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]

参考

如果您在代码中使用 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

如果你真的想要一个普通的 Python 列表,你可以随时调用 list()。

但是,结果是自动排序的,从上面的代码片段可以看出。 如果需要保留列表顺序,请查看numpy unique 而不进行排序

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

list(set(my_not_unique_list))

简单而简短。

仅使用列表压缩的相同顺序唯一列表。

> 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

编辑

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

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

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

通过使用 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

输出将是:

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

首先,您给出的示例不是有效列表。

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

set可以帮助您从列表中过滤掉重复的元素。 它适用于strinttuple元素,但如果您的列表包含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

要从列表中获取唯一值,使用以下代码:

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

重要提示:如果列表中的任何项目不可散列,则上述方法将不起作用,这是可变类型的情况,例如listdict

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

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

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,你可以使用普通的dict

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

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

我很惊讶到目前为止没有人给出直接的顺序保留答案:

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),因此对于长列表也能正常工作。

除了前面的答案,其中说您可以将列表转换为设置,您也可以通过这种方式执行此操作

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']
def setlist(lst=[]):
   return list(set(lst))

Set 是无序唯一元素的集合。 因此,您可以使用如下设置来获取唯一列表:

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

您可以使用集合。 为了清楚起见,我正在解释列表和集合之间的区别。 集合是唯一元素的无序集合。列表是元素的有序集合。 所以,

    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
  1. 在代码的开头,只需将输出列表声明为空: output=[]
  2. 您可以使用此代码来代替您的代码trends=list(set(trends))

我检查内容的唯一性但保留原始顺序的解决方案:

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

编辑:通过使用字典键来检查是否存在而不是为每一行执行整个文件循环可能会更有效,我不会将我的解决方案用于大集合。

使用 set 对列表进行重复数据删除,作为列表返回

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

我知道这是一个老问题,但这是我独特的解决方案:类继承!:

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

然后,如果您想将项目唯一地附加到列表中,您只需在 UniqueList 上调用 appendunique。 因为它继承自一个列表,所以它基本上就像一个列表,所以你可以使用 index() 等函数。因为它返回 true 或 false,你可以找出附加是成功的(唯一项)还是失败的(已经在列表)。

要从列表中获取唯一的项目列表,请使用 for 循环将项目附加到 UniqueList(然后复制到列表中)。

示例使用代码:

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]

对于长数组

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

试试这个函数,它与您的代码类似,但它是一个动态范围。

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

使用以下函数:

def uniquefy_list(input_list):
"""
This function  takes a list as input and return a list containing only unique elements from the input list

"""
output_list=[]
for elm123 in input_list:
    in_both_lists=0
    for elm234 in output_list:
        if elm123 == elm234:
            in_both_lists=1
            break
    if in_both_lists == 0:
        output_list.append(elm123)

return output_list

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM