【问题标题】:What's the most pythonic way to ensure that all elements of a list are different?确保列表的所有元素都不同的最pythonic方法是什么?
【发布时间】:2009-09-30 23:07:02
【问题描述】:

我有一个 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")

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

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

【问题讨论】:

    标签: python list unique


    【解决方案1】:

    可能是这样的:

    if len(x) == len(set(x)):
        print "all elements are unique"
    else:
        print "elements are not unique"
    

    【讨论】:

    • 您可以首先将它们存储在一个集合中,以确保它们都是唯一的。或者将它们存储在一个集合中,但在添加到集合之前检查成员资格。但是,如果您无法控制输入格式,这绝对有效。
    • 集合不一定保持顺序,这可能很重要。
    • 为什么这对这个目的很重要。我要做的就是查看列表在删除重复项后是否具有相同数量的元素。
    【解决方案2】:

    最流行的答案是 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 平方)在不可避免的情况下(一些项目不可散列,例如字典,以及一些不可比较的,例如复数)。

    这段代码的灵感来自伟大的 Tim Peters 的一个旧配方,它的不同之处在于实际生成了一个独特项目的列表(而且到目前为止set 还不存在——它必须使用@ 987654323@...!-),但基本上面临相同的问题。

    【讨论】:

    • 你的意思是v not in L[i+1:] for v,i in enumerate(L)
    【解决方案3】:

    这个怎么样:

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

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

    【讨论】:

      【解决方案4】:

      希望序列中的所有项目都是不可变的——否则,您将无法在序列上调用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
      

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

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

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

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

          【讨论】:

            【解决方案7】:

            我会用这个:

            mylist = [1,2,3,4]
            is_unique = all(mylist.count(x) == 1 for x in mylist)
            

            【讨论】:

              猜你喜欢
              • 2021-07-13
              • 2012-04-20
              • 2011-01-28
              • 2022-06-20
              • 1970-01-01
              • 1970-01-01
              • 2021-07-10
              • 1970-01-01
              • 2020-12-18
              相关资源
              最近更新 更多