8

我在 Python 中有一个作为程序的一部分生成的列表。我有一个强烈的假设,即这些都是不同的,我用一个断言来检查这一点。

这就是我现在这样做的方式:

如果有两个元素:

try:
    assert(x[0] != x[1])
except:
    print debug_info
    raise Exception("throw to caller")

如果有三个:

try:
    assert(x[0] != x[1])
    assert(x[0] != x[2])
    assert(x[1] != x[2])
except:
    print debug_info
    raise Exception("throw to caller")

如果我不得不用四个元素来做这件事,我会发疯的。

有没有更好的方法来确保列表的所有元素都是唯一的?

4

7 回答 7

26

也许是这样的:

if len(x) == len(set(x)):
    print "all elements are unique"
else:
    print "elements are not unique"
于 2009-09-30T23:09:26.827 回答
18

最受欢迎的答案是 O(N)(好!-),但是正如 @Paul 和 @Mark 指出的那样,它们要求列表的项目是可散列的。@Paul 和@Mark 提出的不可散列项的方法都是通用的,但需要 O(N squared) - 即很多。

如果您的列表项目不可散列但具有可比性,那么您可以做得更好......鉴于列表项目的性质,这是一种始终尽可能快地工作的方法。

import itertools

def allunique(L):
  # first try sets -- fastest, if all items are hashable
  try:
    return len(L) == len(set(L))
  except TypeError:
    pass
  # next, try sort -- second fastest, if items are comparable
  try:
    L1 = sorted(L)
  except TypeError:
    pass
  else:
    return all(len(list(g))==1 for k, g in itertools.groupby(L1))
  # fall back to the slowest but most general approach
  return all(v not in L[i+1:] for i, L in enumerate(L))

这是 O(N) 在可行的情况下(所有项目都可散列),O(N log N) 作为最频繁的回退(一些项目不可散列,但都是可比的),O(N 平方) 在不可避免的情况下(某些项目不可散列,例如字典,和一些不可比较的,例如复数)。

这段代码的灵感来自伟大的蒂姆·彼得斯的一个旧配方,它的不同之处在于实际生成了一个独特项目的列表(而且到目前为止set还没有出现——它必须使用dict...!-),但基本上面临相同的问题。

于 2009-10-01T01:45:12.937 回答
7

这个怎么样:

if len(x) != len(set(x)):
    raise Exception("throw to caller")

这假设其中的元素x是可散列的。

于 2009-09-30T23:11:09.333 回答
2

希望您的序列中的所有项目都是不可变的——如果不是,您将无法调用set该序列。

>>> set( ([1,2], [3,4]) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

如果您确实有可变项目,则无法对这些项目进行哈希处理,并且您几乎必须反复检查列表:

def isUnique(lst):
    for i,v in enumerate(lst):
        if v in lst[i+1:]:
            return False
    return True

>>> isUnique( ([1,2], [3,4]) )
True
>>> isUnique( ([1,2], [3,4], [1,2]) )
False
于 2009-09-30T23:31:47.467 回答
1

在构建列表时,您可以检查该值是否已经存在,例如:

if x in y:
     raise Exception("Value %s already in y" % x)
else:
     y.append(x)

这样做的好处是会报告冲突变量。

于 2009-09-30T23:40:31.707 回答
0

您可以处理该列表以创建一个已知唯一的副本:

def make_unique(seq): 
    t = type(seq) 
    seen = set()
    return t(c for c in seq if not (c in seen or seen.add(c)))

或者如果 seq 元素不可散列:

def unique1(seq):
    t = type(seq) 
    seen = [] 
    return t(c for c in seq if not (c in seen or seen.append(c)))

这将使项目保持有序(当然,省略重复项)。

于 2009-10-01T01:22:28.383 回答
0

我会用这个:

mylist = [1,2,3,4]
is_unique = all(mylist.count(x) == 1 for x in mylist)
于 2009-10-01T10:32:14.297 回答