检查列表中的所有元素是否都是唯一的

use*_*312 92 python algorithm list unique

检查列表中的所有元素是否唯一的最佳方法(在传统方式中最好)是什么?

我目前采用的方法Counter是:

>>> x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
>>> counter = Counter(x)
>>> for values in counter.itervalues():
        if values > 1: 
            # do something
Run Code Online (Sandbox Code Playgroud)

我可以做得更好吗?

yan*_*yan 146

不是最有效,但直接和简洁:

if len(x) > len(set(x)):
   pass # do something
Run Code Online (Sandbox Code Playgroud)

可能不会对短名单产生太大影响.

  • 你是说==? (4认同)
  • 够公平,很好的解决方案。我处理的元素很少 < 500,所以这应该做我想做的。 (2认同)
  • 对于那些担心长列表效率的人来说,这对于实际上是唯一的长列表(所有元素都需要检查)非常有效。对于实际唯一的列表,提早退出解决方案需要更长的时间(在我的测试中大约要长2倍)。因此...如果您希望大多数列表都是唯一的,请使用此简单的设置长度检查解决方案。如果您希望大多数列表不是唯一的,请使用提前退出解决方案。使用哪个取决于您的用例。 (2认同)
  • 这个答案很好。但是,我们要小心:当“x”中的元素不唯一时,“len(x) > len(set(x))”为 True。这个问题的标题提出了完全相反的问题:“检查列表中的所有元素是否*都是*唯一的” (2认同)

Pau*_*McG 90

这是一个双线,也将提前退出:

>>> def allUnique(x):
...     seen = set()
...     return not any(i in seen or seen.add(i) for i in x)
...
>>> allUnique("ABCDEF")
True
>>> allUnique("ABACDEF")
False
Run Code Online (Sandbox Code Playgroud)

如果x的元素不可清除,那么您将不得不求助于使用以下列表seen:

>>> def allUnique(x):
...     seen = list()
...     return not any(i in seen or seen.append(i) for i in x)
...
>>> allUnique([list("ABC"), list("DEF")])
True
>>> allUnique([list("ABC"), list("DEF"), list("ABC")])
False
Run Code Online (Sandbox Code Playgroud)

  • +1清除,如果不需要,不会遍历整个列表. (5认同)

650*_*502 21

早期解决方案可能是

def unique_values(g):
    s = set()
    for x in g:
        if x in s: return False
        s.add(x)
    return True
Run Code Online (Sandbox Code Playgroud)

但是对于小型病例或早期退出不是常见的情况,那么我希望len(x) != len(set(x))是最快的方法.

  • 您可以通过在`s = set()之后放置以下行来缩短它... ...`不返回任何(s.add(x)如果x不在s中,则为x,其中为x) (2认同)

loc*_*jay 12

速度:

import numpy as np
x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
np.unique(x).size == len(x)
Run Code Online (Sandbox Code Playgroud)


Grz*_*zki 10

如何将所有条目添加到集合并检查其长度?

len(set(x)) == len(x)
Run Code Online (Sandbox Code Playgroud)


Tug*_*tes 9

替代a set,你可以使用a dict.

len({}.fromkeys(x)) == len(x)
Run Code Online (Sandbox Code Playgroud)

  • 我认为在一组中使用dict绝对没有优势.似乎不必要地使事情复杂化. (9认同)

Nic*_*mer 6

我将建议的解决方案与perfplot进行了比较,发现

len(lst) == len(set(lst))
Run Code Online (Sandbox Code Playgroud)

确实是最快的解决方案。如果列表中存在早期重复项,则应首选一些恒定时间解决方案。

在此输入图像描述

在此输入图像描述


重现情节的代码:

import perfplot
import numpy as np
import pandas as pd


def len_set(lst):
    return len(lst) == len(set(lst))


def set_add(lst):
    seen = set()
    return not any(i in seen or seen.add(i) for i in lst)


def list_append(lst):
    seen = list()
    return not any(i in seen or seen.append(i) for i in lst)


def numpy_unique(lst):
    return np.unique(lst).size == len(lst)


def set_add_early_exit(lst):
    s = set()
    for item in lst:
        if item in s:
            return False
        s.add(item)
    return True


def pandas_is_unique(lst):
    return pd.Series(lst).is_unique


def sort_diff(lst):
    return not np.any(np.diff(np.sort(lst)) == 0)


b = perfplot.bench(
    setup=lambda n: list(np.arange(n)),
    title="All items unique",
    # setup=lambda n: [0] * n,
    # title="All items equal",
    kernels=[
        len_set,
        set_add,
        list_append,
        numpy_unique,
        set_add_early_exit,
        pandas_is_unique,
        sort_diff,
    ],
    n_range=[2**k for k in range(18)],
    xlabel="len(lst)",
)

b.save("out.png")
b.show()
Run Code Online (Sandbox Code Playgroud)