繁体   English   中英

删除列表中的重复项

[英]Removing duplicates in lists

如何检查列表是否有重复项并返回没有重复项的新列表?

获取唯一项集合的常用方法是使用set 集合是不同对象的无序集合。 要从任何可迭代对象创建一个集合,您只需将其传递给内置的set()函数即可。 如果您稍后再次需要一个真正的列表,您可以类似地将集合传递给list()函数。

以下示例应涵盖您尝试执行的任何操作:

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]

正如您从示例结果中看到的,原始顺序没有得到维护 如上所述,集合本身是无序集合,因此顺序丢失。 将集合转换回列表时,会创建任意顺序。

维持秩序

如果顺序对您很重要,那么您将不得不使用不同的机制。 一个非常常见的解决方案是依靠OrderedDict在插入过程中保持键的顺序:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

从 Python 3.7 开始,内置字典也保证保持插入顺序,因此如果您使用的是 Python 3.7 或更高版本(或 CPython 3.6),您也可以直接使用它:

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

请注意,这可能会产生一些开销,即先创建字典,然后从中创建列表。 如果您实际上不需要保留顺序,通常最好使用集合,特别是因为它为您提供了更多的操作。 查看此问题以获取更多详细信息以及在删除重复项时保留顺序的替代方法。


最后请注意, setOrderedDict / dict解决方案都要求您的项目是可散列的 这通常意味着它们必须是不可变的。 如果您必须处理不可散列的项目(例如列表对象),那么您将不得不使用一种缓慢的方法,在这种方法中,您基本上必须将每个项目与嵌套循环中的每个其他项目进行比较。

在 Python 2.7 中,从可迭代对象中删除重复项同时保持其原始顺序的新方法是:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

在 Python 3.5 中, OrderedDict 有一个 C 实现。 我的时间安排表明,这现在是 Python 3.5 的各种方法中最快和最短的。

在 Python 3.6 中,常规 dict 变得既有序又紧凑。 (此功能适用于 CPython 和 PyPy,但在其他实现中可能不存在)。 这为我们提供了一种新的最快的重复数据删除方法,同时保持顺序:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

在 Python 3.7 中,常规 dict 保证在所有实现中都是有序的。 因此,最短和最快的解决方案是:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

这是一个单行: list(set(source_list))会做的伎俩。

set是不可能有重复的东西。

更新:保持顺序的方法是两行:

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

这里我们使用OrderedDict记住键的插入顺序的事实,并且在更新特定键的值时不会更改它。 我们插入True作为值,但我们可以插入任何东西,只是不使用值。 set很像带有忽略值的dict 。)

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
       if i not in s:
          s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]

如果您不在乎顺序,请执行以下操作:

def remove_duplicates(l):
    return list(set(l))

一个set保证没有重复。

创建一个新列表,保留L中重复项的第一个元素的顺序

newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]

例如, if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]那么newlist将是[1,2,3,4,5]

这会检查每个新元素在添加之前没有出现在列表中。 它也不需要进口。

也有使用 Pandas 和 Numpy 的解决方案。 它们都返回 numpy 数组,所以如果你想要一个列表,你必须使用函数.tolist()

t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']

熊猫解决方案

使用 Pandas 函数unique()

import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']

麻木解决方案

使用 numpy 函数unique()

import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']

请注意, numpy.unique() 也会对 values 进行排序 所以列表t2返回排序。 如果您想保留订单,请使用此答案

_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']

与其他解决方案相比,该解决方案并不那么优雅,但是,与 pandas.unique() 相比,numpy.unique() 还允许您检查嵌套数组是否沿着一个选定的轴唯一。

一位同事已将接受的答案作为他代码的一部分发送给我,以便今天进行代码审查。 虽然我当然欣赏问题答案的优雅,但我对表现并不满意。 我已经尝试过这个解决方案(我使用set来减少查找时间)

def ordered_set(in_list):
    out_list = []
    added = set()
    for val in in_list:
        if not val in added:
            out_list.append(val)
            added.add(val)
    return out_list

为了比较效率,我使用了 100 个整数的随机样本 - 62 个是唯一的

from random import randint
x = [randint(0,100) for _ in xrange(100)]

In [131]: len(set(x))
Out[131]: 62

以下是测量结果

In [129]: %timeit list(OrderedDict.fromkeys(x))
10000 loops, best of 3: 86.4 us per loop

In [130]: %timeit ordered_set(x)
100000 loops, best of 3: 15.1 us per loop

那么,如果从解决方案中删除 set 会发生什么?

def ordered_set(inlist):
    out_list = []
    for val in inlist:
        if not val in out_list:
            out_list.append(val)
    return out_list

结果并不像OrderedDict那样糟糕,但仍然是原始解决方案的 3 倍以上

In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop

在这个答案中,将有两个部分:两个独特的解决方案,以及特定解决方案的速度图。

删除重复项

这些答案中的大多数只删除了可散列的重复项,但这个问题并不意味着它不仅需要可散列的项目,这意味着我将提供一些不需要可散列项的解决方案。

collections.Counter是标准库中的一个强大的工具,可以完美地解决这个问题。 只有另一种解决方案甚至包含 Counter 。 但是,该解决方案也仅限于可散列的键。

为了在 Counter 中允许不可散列的键,我创建了一个 Container 类,它将尝试获取对象的默认散列函数,但如果失败,它将尝试其标识函数。 它还定义了一个eq和一个哈希方法。 这应该足以在我们的解决方案中允许不可散列的项目。 不可散列对象将被视为可散列对象。 然而,这个散列函数对不可散列的对象使用标识,这意味着两个均不可散列的相等对象将不起作用。 我建议您覆盖它,并将其更改为使用等效可变类型的hash(tuple(my_list))例如,如果my_list是列表,则使用hash(tuple(my_list)) )。

我也做了两个解决方案。 另一种保持项目顺序的解决方案,使用名为“OrderedCounter”的 OrderedDict 和 Counter 的子类。 现在,这里是功能:

from collections import OrderedDict, Counter

class Container:
    def __init__(self, obj):
        self.obj = obj
    def __eq__(self, obj):
        return self.obj == obj
    def __hash__(self):
        try:
            return hash(self.obj)
        except:
            return id(self.obj)

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)
    
def remd(sequence):
    cnt = Counter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

def oremd(sequence):
    cnt = OrderedCounter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

remd是无序排序,而oremd是有序排序。 您可以清楚地分辨出哪个更快,但无论如何我都会解释。 无序排序稍微快一点,因为它不存储项目的顺序。

现在,我还想展示每个答案的速度比较。 所以,我现在就这样做。

哪个功能最快?

为了删除重复项,我从几个答案中收集了 10 个函数。 我计算了每个函数的速度,并使用matplotlib.pyplot将其放入图形中。

我将其分为三轮绘图。 可散列是任何可以散列的对象,不可散列是任何不能散列的对象。 有序序列是保持顺序的序列,无序序列不保持顺序。 现在,这里还有一些术语:

Unordered Hashable适用于任何删除重复项的方法,这些方法不一定要保持顺序。 它不必对不可散列的人起作用,但它可以。

Ordered Hashable适用于任何保持列表中项目顺序的方法,但它不一定适用于不可散列的项目,但它可以。

Ordered Unhashable是任何保持列表中项目顺序的方法,并且适用于 unhashable。

在 y 轴上是它花费的秒数。

x 轴上是应用函数的数字。

我使用以下理解为无序散列和有序散列生成了序列: [list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]

对于有序不可散列: [[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]

请注意,范围中有一个step ,因为没有它,这将花费 10 倍的时间。 也因为在我个人看来,我认为它可能看起来更容易阅读。

还要注意图例上的键是我试图猜测的函数实现中最重要的部分。 至于哪个功能最差或最好? 该图不言自明。

解决了这个问题,这里是图表。

无序哈希

无序哈希 (放大) 无序 Hashables 放大

有序哈希

有序哈希 (放大) 有序 Hashables 放大

有序不可哈希

有序不可哈希 (放大) 有序 Unhashables 放大

另一种做法:

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]

简单易行:

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]

输出:

>>> cleanlist 
[1, 2, 3, 5, 6, 7, 8]

我的列表中有一个字典,所以我不能使用上述方法。 我得到了错误:

TypeError: unhashable type:

因此,如果您关心订单和/或某些项目是不可哈希的 然后你可能会发现这很有用:

def make_unique(original_list):
    unique_list = []
    [unique_list.append(obj) for obj in original_list if obj not in unique_list]
    return unique_list

有些人可能认为具有副作用的列表理解不是一个好的解决方案。 这是一个替代方案:

def make_unique(original_list):
    unique_list = []
    map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
    return unique_list

很晚的答案。 如果您不关心列表顺序,则可以使用带有set唯一性的*arg扩展来删除重复项,即:

l = [*{*l}]

演示

如果您想保留顺序,而不使用任何外部模块,这里有一个简单的方法:

>>> t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9]
>>> list(dict.fromkeys(t))
[1, 9, 2, 3, 4, 5, 6, 7, 8]

注意:此方法保留了出现的顺序,因此,如上所示,9 会在 1 之后,因为它是第一次出现。 然而,这与您所做的结果相同

from collections import OrderedDict
ulist=list(OrderedDict.fromkeys(l))

但它更短,运行速度更快。

这是有效的,因为每次fromkeys函数尝试创建一个新键时,如果该值已经存在,它将简单地覆盖它。 但是,这fromkeys不会影响字典,因为fromkeys创建了一个字典,其中所有键的值都为None ,因此它可以有效地消除所有重复项。

到目前为止,我在这里看到的所有保留顺序的方法要么使用简单的比较(最多为 O(n^2) 时间复杂度),要么使用仅限于可哈希输入的重量级OrderedDicts / set + list组合。 这是一个与哈希无关的 O(nlogn) 解决方案:

更新添加了key参数、文档和 Python 3 兼容性。

# from functools import reduce <-- add this import on Python 3

def uniq(iterable, key=lambda x: x):
    """
    Remove duplicates from an iterable. Preserves order. 
    :type iterable: Iterable[Ord => A]
    :param iterable: an iterable of objects of any orderable type
    :type key: Callable[A] -> (Ord => B)
    :param key: optional argument; by default an item (A) is discarded 
    if another item (B), such that A == B, has already been encountered and taken. 
    If you provide a key, this condition changes to key(A) == key(B); the callable 
    must return orderable objects.
    """
    # Enumerate the list to restore order lately; reduce the sorted list; restore order
    def append_unique(acc, item):
        return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc 
    srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
    return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))] 

你也可以这样做:

>>> t = [1, 2, 3, 3, 2, 4, 5, 6]
>>> s = [x for i, x in enumerate(t) if i == t.index(x)]
>>> s
[1, 2, 3, 4, 5, 6]

上述工作的原因是index方法只返回元素的第一个索引。 重复元素具有更高的索引。 请参阅此处

list.index(x[, start[, end]])
在值为 x 的第一个项目的列表中返回从零开始的索引。 如果没有这样的项目,则引发 ValueError。

从列表中删除重复项的最佳方法是使用 python 中可用的set()函数,再次将该集合转换为列表

In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']

您可以使用set删除重复项:

mylist = list(set(mylist))

但请注意,结果将是无序的。 如果这是一个问题:

mylist.sort()

通过排序保留减少变体:

假设我们有列表:

l = [5, 6, 6, 1, 1, 2, 2, 3, 4]

减少变体(低效):

>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]

速度提高 5 倍但更复杂

>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]

解释:

default = (list(), set())
# user list to keep order
# use set to make lookup faster

def reducer(result, item):
    if item not in result[1]:
        result[0].append(item)
        result[1].add(item)
    return result

reduce(reducer, l, default)[0]

一种更好的方法可能是,

import pandas as pd

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)

#> [1, 2, 3, 5, 6, 7, 8]

并且订单保持不变。

尝试使用集合:

import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])

print t | t1
print t - t1

您可以使用以下功能:

def rem_dupes(dup_list): 
    yooneeks = [] 
    for elem in dup_list: 
        if elem not in yooneeks: 
            yooneeks.append(elem) 
    return yooneeks

示例

my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']

用法:

rem_dupes(my_list)

['this', 'is', 'a', 'list', 'with', 'dupicates', 'in', 'the']

还有许多其他答案提出了不同的方法来执行此操作,但它们都是批处理操作,其中一些会丢弃原始顺序。 根据您的需要,这可能没问题,但是如果您想按照每个值的第一个实例的顺序迭代这些值,并且您想即时删除重复项而不是一次性删除所有重复项,则可以使用这个发电机:

def uniqify(iterable):
    seen = set()
    for item in iterable:
        if item not in seen:
            seen.add(item)
            yield item

这将返回一个生成器/迭代器,因此您可以在任何可以使用迭代器的地方使用它。

for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
    print(unique_item, end=' ')

print()

输出:

1 2 3 4 5 6 7 8

如果你确实想要一个list ,你可以这样做:

unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))

print(unique_list)

输出:

[1, 2, 3, 4, 5, 6, 7, 8]

不使用集合

data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
    if dat not in uni_data:
        uni_data.append(dat)

print(uni_data) 

这个关心订单没有太多麻烦(OrderdDict 和其他人)。 可能不是最 Pythonic 的方式,也不是最短的方式,但诀窍是:

def remove_duplicates(list):
    ''' Removes duplicate items from a list '''
    singles_list = []
    for element in list:
        if element not in singles_list:
            singles_list.append(element)
    return singles_list

下面的代码很容易删除列表中的重复项

def remove_duplicates(x):
    a = []
    for i in x:
        if i not in a:
            a.append(i)
    return a

print remove_duplicates([1,2,2,3,3,4])

它返回 [1,2,3,4]

这是与回复中列出的其他人相比的最快的 Pythonic 解决方案。

使用短路评估的实现细节允许使用足够快的列表理解。 visited.add(item)总是返回None作为结果,它被评估为False ,因此or的右侧将始终是此类表达式的结果。

自己计时

def deduplicate(sequence):
    visited = set()
    adder = visited.add  # get rid of qualification overhead
    out = [adder(item) or item for item in sequence if item not in visited]
    return out

使用集合

a = [0,1,2,3,4,3,3,4]
a = list(set(a))
print a

使用独特的

import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a

Python 3 中非常简单的方法:

>>> n = [1, 2, 3, 4, 1, 1]
>>> n
[1, 2, 3, 4, 1, 1]
>>> m = sorted(list(set(n)))
>>> m
[1, 2, 3, 4]

很遗憾。 这里的大多数答案要么不保留顺序,要么太长。 这是一个简单的,保留顺序的答案。

s = [1,2,3,4,5,2,5,6,7,1,3,9,3,5]
x=[]

[x.append(i) for i in s if i not in x]
print(x)

这将为您提供 x 删除重复项但保留顺序。

Python 内置类型的魔力

在python中,处理这种复杂的情况非常容易,而且只能通过python的内置类型来处理。

让我告诉你怎么做!

方法一:一般情况

删除列表中重复元素并保持排序顺序的方式( 1行代码

line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
new_line = sorted(set(line), key=line.index) # remove duplicated element
print(new_line)

你会得到结果

[1, 2, 3, 5, 6, 7, 8]

方法二:特殊情况

TypeError: unhashable type: 'list'

处理 unhashable 的特殊情况( 3 行代码

line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']]

tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list

print (new_line)

你会得到结果:

[
  ['16.4966155686595', '-27.59776154691', '52.3786295521147'], 
  ['17.6508629295574', '-27.143305738671', '47.534955022564'], 
  ['18.8051102904552', '-26.688849930432', '42.6912804930134'], 
  ['19.5504702331098', '-26.205884452727', '37.7709192714727'], 
  ['20.2929416861422', '-25.722717575124', '32.8500163147157']
]

因为元组是可散列的,您可以轻松地在列表和元组之间转换数据

我用纯python函数做到了这一点。 当您的items值为 JSON 时,这有效。

[i for n, i in enumerate(items) if i not in items[n + 1 :]]

这是一个示例,返回不保留重复顺序的列表。 不需要任何外部进口。

def GetListWithoutRepetitions(loInput):
    # return list, consisting of elements of list/tuple loInput, without repetitions.
    # Example: GetListWithoutRepetitions([None,None,1,1,2,2,3,3,3])
    # Returns: [None, 1, 2, 3]

    if loInput==[]:
        return []

    loOutput = []

    if loInput[0] is None:
        oGroupElement=1
    else: # loInput[0]<>None
        oGroupElement=None

    for oElement in loInput:
        if oElement<>oGroupElement:
            loOutput.append(oElement)
            oGroupElement = oElement
    return loOutput

如果要删除重复项(就地编辑而不是返回新列表)而不使用内置集,dict.keys,uniqify,counter,请选中此选项

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> for i in t:
...     if i in t[t.index(i)+1:]:
...         t.remove(i)
... 
>>> t
[3, 1, 2, 5, 6, 7, 8]

我认为转换为set是删除重复项的最简单方法:

list1 = [1,2,1]
list1 = list(set(list1))
print list1

我没有看到不可散列值的答案,一个班轮,n log n,只有标准库,所以这是我的答案:

list(map(operator.itemgetter(0), itertools.groupby(sorted(items))))

或者作为生成器函数:

def unique(items: Iterable[T]) -> Iterable[T]:
    """For unhashable items (can't use set to unique) with a partial order"""
    yield from map(operator.itemgetter(0), itertools.groupby(sorted(items)))

我已经将各种建议与perfplot进行了比较。 事实证明,如果输入数组没有重复元素,则所有方法或多或少都一样快,与输入数据是 Python 列表还是 NumPy 数组无关。

在此处输入图片说明

如果输入数组很大,但只包含一个唯一元素,那么如果输入数据是列表,则setdictnp.unique方法是持续时间 如果它是一个 NumPy 数组, np.unique比其他替代方案快 10 倍左右。

在此处输入图片说明

令我惊讶的是,这些也不是恒定时间的操作。


重现图的代码:

import perfplot
import numpy as np
import matplotlib.pyplot as plt


def setup_list(n):
    # return list(np.random.permutation(np.arange(n)))
    return [0] * n


def setup_np_array(n):
    # return np.random.permutation(np.arange(n))
    return np.zeros(n, dtype=int)


def list_set(data):
    return list(set(data))


def numpy_unique(data):
    return np.unique(data)


def list_dict(data):
    return list(dict.fromkeys(data))


b = perfplot.bench(
    setup=[
        setup_list,
        setup_list,
        setup_list,
        setup_np_array,
        setup_np_array,
        setup_np_array,
    ],
    kernels=[list_set, numpy_unique, list_dict, list_set, numpy_unique, list_dict],
    labels=[
        "list(set(lst))",
        "np.unique(lst)",
        "list(dict(lst))",
        "list(set(arr))",
        "np.unique(arr)",
        "list(dict(arr))",
    ],
    n_range=[2 ** k for k in range(23)],
    xlabel="len(array)",
    equality_check=None,
)
# plt.title("input array = [0, 1, 2,..., n]")
plt.title("input array = [0, 0,..., 0]")
b.save("out.png")
b.show()

要删除重复项,请将其设为 SET,然后再次设为 LIST 并打印/使用它。 一个集合保证有唯一的元素。 例如 :

a = [1,2,3,4,5,9,11,15]
b = [4,5,6,7,8]
c=a+b
print c
print list(set(c)) #one line for getting unique elements of c

输出如下(在python 2.7中检查)

[1, 2, 3, 4, 5, 9, 11, 15, 4, 5, 6, 7, 8]  #simple list addition with duplicates
[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15] #duplicates removed!!

它需要安装第 3 方模块,但包iteration_utilities unique_everseen程序包含一个unique_everseen 1函数,可以在保留顺序的同时删除所有重复项:

>>> from iteration_utilities import unique_everseen

>>> list(unique_everseen(['a', 'b', 'c', 'd'] + ['a', 'c', 'd']))
['a', 'b', 'c', 'd']

如果您想避免列表添加操作的开销,您可以使用itertools.chain代替:

>>> from itertools import chain
>>> list(unique_everseen(chain(['a', 'b', 'c', 'd'], ['a', 'c', 'd'])))
['a', 'b', 'c', 'd']

如果列表中有不可哈希的项目(例如列表),则unique_everseen也有效:

>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen([['a'], ['b'], 'c', 'd'] + ['a', 'c', 'd']))
[['a'], ['b'], 'c', 'd', 'a']

但是,这将比项目可散列时(慢得多)慢。


1披露:我是iteration_utilities实用程序库的作者。

你可以简单地使用集合来做到这一点。

Step1:获取列表的不同元素
Step2获取列表的公共元素
Step3组合它们

In [1]: a = ["apples", "bananas", "cucumbers"]

In [2]: b = ["pears", "apples", "watermelons"]

In [3]: set(a).symmetric_difference(b).union(set(a).intersection(b))
Out[3]: {'apples', 'bananas', 'cucumbers', 'pears', 'watermelons'}
def remove_duplicates(A):
   [A.pop(count) for count,elem in enumerate(A) if A.count(elem)!=1]
   return A

删除重复项的列表理解

如果你不关心顺序并且想要一些不同于上面建议的 Pythonic 方式的东西(也就是说,它可以在面试中使用)那么:

def remove_dup(arr):
    size = len(arr)
    j = 0    # To store index of next unique element
    for i in range(0, size-1):
        # If current element is not equal
        # to next element then store that
        # current element
        if(arr[i] != arr[i+1]):
            arr[j] = arr[i]
            j+=1

    arr[j] = arr[size-1] # Store the last element as whether it is unique or repeated, it hasn't stored previously

    return arr[0:j+1]

if __name__ == '__main__':
    arr = [10, 10, 1, 1, 1, 3, 3, 4, 5, 6, 7, 8, 8, 9]
    print(remove_dup(sorted(arr)))

时间复杂度:O(n)

辅助空间:O(n)

参考: http : //www.geeksforgeeks.org/remove-duplicates-sorted-array/

这里有很多答案使用set(..) (鉴于元素是可散列的,因此速度很快)或列表(其缺点是会导致O(n 2 )算法。

我提出的函数是一个混合函数:我们对散列的项目使用set(..) ,对不可散列的项目使用list(..) 此外,它被实现为一个生成器,这样我们就可以限制项目的数量,或者做一些额外的过滤。

最后,我们还可以使用key参数来指定元素应该以何种方式唯一。 例如,如果我们想过滤一个字符串列表,使得输出中的每个字符串都有不同的长度,我们可以使用它。

def uniq(iterable, key=lambda x: x):
    seens = set()
    seenl = []
    for item in iterable:
        k = key(item)
        try:
            seen = k in seens
        except TypeError:
            seen = k in seenl
        if not seen:
            yield item
            try:
                seens.add(k)
            except TypeError:
                seenl.append(k)

例如,我们现在可以像这样使用:

>>> list(uniq(["apple", "pear", "banana", "lemon"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", "lemon", "banana"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"], len))
['apple', 'pear', {}, 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"]))
['apple', 'pear', {}, 'lemon', [], 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", {}, "banana"]))
['apple', 'pear', {}, 'lemon', 'banana']

因此,它是一个唯一性过滤器,可以处理任何可迭代并过滤掉唯一性,无论这些是否是可散列的。

它做出一个假设:如果一个对象是可散列的,而另一个不是,则这两个对象永远不会相等。 严格来说,这可能会发生,尽管这种情况非常罕见。

另一种解决方案可能如下。 从列表中创建一个以项目为键,索引为值的字典,然后打印字典键。

>>> lst = [1, 3, 4, 2, 1, 21, 1, 32, 21, 1, 6, 5, 7, 8, 2]
>>>
>>> dict_enum = {item:index for index, item in enumerate(lst)}
>>> print dict_enum.keys()
[32, 1, 2, 3, 4, 5, 6, 7, 8, 21]

为了完整起见,由于这是一个非常受欢迎的问题, toolz库提供了一个unique功能:

>>> tuple(unique((1, 2, 3)))
(1, 2, 3)
>>> tuple(unique((1, 2, 1, 3)))
(1, 2, 3)
def remove_duplicates(input_list):
  if input_list == []:
    return []
  #sort list from smallest to largest
  input_list=sorted(input_list)
  #initialize ouput list with first element of the       sorted input list
  output_list = [input_list[0]]
  for item in input_list:
    if item >output_list[-1]:
      output_list.append(item)
  return output_list   

这只是一个可读的函数,很容易理解,我使用了 dict 数据结构,我使用了一些内置函数和更好的 O(n) 复杂度

def undup(dup_list):
    b={}
    for i in dup_list:
        b.update({i:1})
    return b.keys()
a=["a",'b','a']
print undup(a)

免责声明:您可能会遇到缩进错误(如果复制和粘贴),请在粘贴前使用带有适当缩进的上述代码

Python 内置了很多函数,你可以使用 set() 去除列表内的重复项。 根据您的示例,下面有两个列表 t 和 t2

t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
result = list(set(t) - set(t2))
result

答案:['b']

有时您需要就地删除重复项,而无需创建新列表。 例如,列表很大,或将其保留为卷影副本

from collections import Counter
cntDict = Counter(t)
for item,cnt in cntDict.items():
    for _ in range(cnt-1):
        t.remove(item)

如果您的列表是有序的,您可以使用以下方法对其进行迭代,跳过重复的值。 这对于处理具有低内存消耗的大列表特别有用,以避免构建dictset的成本:

def uniq(iterator):
    prev = None
    for item in iterator:
        if item != prev:
            prev = item
            yield item

然后:

for item in uniq([1, 1, 3, 5, 5, 6]):
    print(item, end=' ')

输出将是: 1 3 5 6

要返回列表对象,您可以执行以下操作:

>>> print(list(uniq([1, 1, 3, 5, 5, 6])))
[1, 3, 5, 6]
  • 您可以使用 Python集或 dict.fromkeys()方法删除重复项

  • dict.fromkeys()方法列表转换为字典 字典不能包含重复值,因此 dict.fromkeys() 返回只有唯一值的字典。

  • Sets和字典一样,不能包含重复的值 如果我们将列表转换为集合则会删除所有重复项

方法一:天真的方法
mylist = [5, 10, 15, 20, 3, 15, 25, 20, 30, 10, 100]

uniques = []

for i in mylist:

    if i not in uniques:

       uniques.append(i)

print(uniques)
方法 2:使用 set()
mylist = [5, 10, 15, 20, 3, 15, 25, 20, 30, 10, 100]

myset = set(mylist)

print(list(myset))

使用集合,但保留顺序

unique = set()
[unique.add(n) or n for n in l if n not in unique]

您可以比较集合和列表的长度,并将集合项保存到列表中。

if len(t) != len(set(t)):
    t = [x for x in set(t)]
     
list(set(x))

很短,它有效。

list_with_unique_items = list(set(list_with_duplicates))
Test = [1,8,2,7,3,4,5,1,2,3,6]
Test.sort()
i=1
while i< len(Test):
  if Test[i] == Test[i-1]:
    Test.remove(Test[i])
  i= i+1
print(Test)

检查字符串 'a' 和 'b'

clean_list = []
    for ele in raw_list:
        if 'b' in ele or 'a' in ele:
            pass
        else:
            clean_list.append(ele)
Write a Python program to create a list of numbers by taking input from the user and then remove  the duplicates from the list. You can take input of non-zero numbers, with an appropriate  prompt, from the user until the user enters a zero to create the list assuming that the numbers  are non-zero.  
Sample Input: [10, 34, 18, 10, 12, 34, 18, 20, 25, 20]  
Output: [10, 34, 18, 12, 20, 25] 

 lst = []
print("ENTER ZERO NUMBER FOR EXIT !!!!!!!!!!!!")
print("ENTER LIST ELEMENTS  :: ")
while True:
    n = int(input())
    if n == 0 :
       print("!!!!!!!!!!! EXIT !!!!!!!!!!!!")
       break
    else :
        lst.append(n)
print("LIST ELEMENR ARE :: ",lst)
#dup = set()
uniq = []
for x in lst:
    if x not in uniq:
        uniq.append(x)
       # dup.add(x)
print("UNIQUE ELEMENTS IN LIST ARE :: ",uniq)

暂无
暂无

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

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