我如何检查一个列表是否有任何重复,并返回一个没有重复的新列表?


当前回答

到目前为止,我看到的所有保持顺序的方法要么使用朴素比较(时间复杂度最多为O(n^2)),要么使用限制于可哈希输入的重载OrderedDicts/set+list组合。下面是一个与哈希无关的O(nlogn)解决方案:

更新增加了关键参数、文档和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]]))] 

其他回答

如果你不关心顺序,就这样做:

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

一个集合保证没有重复项。

有时你需要删除重复的项目,而不需要创建新的列表。例如,列表很大,或者将其作为影子副本保存

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

下面的代码是简单的删除重复列表

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]

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

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

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

如果输入数组很大,但只包含一个唯一元素,则set、dict和np。如果输入数据是一个列表,唯一方法是常量时间的。如果是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()