【问题标题】:Checking if all elements in a list are unique检查列表中的所有元素是否唯一
【发布时间】:2011-07-13 18:47:10
【问题描述】:

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

我目前使用Counter 的方法是:

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

我可以做得更好吗?

【问题讨论】:

    标签: python algorithm list unique


    【解决方案1】:

    不是最有效的,但直截了当:

    if len(x) > len(set(x)):
       pass # do something
    

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

    【讨论】:

    • 这也是我所做的。不过,对于大型列表可能效率不高。
    • 不一定,如果列表中有重复元素(示例中的“#do something”),它将执行条件的主体。
    • 很公平,很好的解决方案。我处理的元素几乎少于 500 个,所以这应该可以满足我的要求。
    • 对于那些担心长列表效率的人来说,这对于实际上是唯一的长列表(所有元素都需要检查)是有效的。对于实际唯一的列表,早期退出解决方案需要更长的时间(在我的测试中大约长 2 倍)。所以...如果您希望大多数列表都是唯一的,请使用这个简单的设置长度检查解决方案。如果您希望大多数列表不是唯一的,请使用提前退出解决方案。使用哪一个取决于您的用例。
    • 这个答案很好。但是,我们在这里要小心:当x 中的元素不是唯一的时,len(x) > len(set(x)) 为 True。这个问题的标题正好相反:“检查列表中的所有元素是否都是唯一的”
    【解决方案2】:

    这是一个也可以提前退出的两条线:

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

    如果 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
    

    【讨论】:

    • +1 干净,如果不需要,不会遍历整个列表。
    • @paul-mcguire: 你愿意在兼容 Apache 2.0 的许可下许可这个代码 sn-p(例如,Apache 2、2/3-line BSD、MIT、X11、zlib) .我想在我正在使用的 Apache 2.0 项目中使用它,并且因为 StackOverflow 的许可条款是 fubar,所以我问你是原作者。
    • 我已经使用 MIT 许可证发布了其他代码,所以这对我来说适用于这个 sn-p。有什么特别需要我做的吗?
    【解决方案3】:

    一个提前退出的解决方案可能是

    def unique_values(g):
        s = set()
        for x in g:
            if x in s: return False
            s.add(x)
        return True
    

    但是,对于小型案例,或者如果提前退出不是常见情况,那么我希望 len(x) != len(set(x)) 是最快的方法。

    【讨论】:

    • 我接受了另一个答案,因为我并不是特别在寻找优化。
    • 您可以通过在s = set()之后添加以下行来缩短它...return not any(s.add(x) if x not in s else True for x in g)
    • 如果提前退出不常见,你能解释一下为什么你会期望len(x) != len(set(x)) 比这更快吗?两个操作不是 O(len(x)) 吗? (其中x 是原始列表)
    • 哦,我明白了:您的方法不是 O(len(x)) 因为您检查了 O(len(x)) 内部的if x in s for 循环。
    【解决方案4】:

    速度:

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

    【讨论】:

      【解决方案5】:

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

      len(set(x)) == len(x)
      

      【讨论】:

      • 在 yan 之后一秒回答,哎哟。短而甜。有什么理由不使用此解决方案?
      • 并非所有序列(尤其是生成器)都支持len()
      【解决方案6】:

      替代set,您可以使用dict

      len({}.fromkeys(x)) == len(x)
      

      【讨论】:

      • 我认为使用 dict 绝对没有优势。似乎不必要地使事情复杂化。
      【解决方案7】:

      完全是另一种方法,使用 sorted 和 groupby:

      from itertools import groupby
      is_unique = lambda seq: all(sum(1 for _ in x[1])==1 for x in groupby(sorted(seq)))
      

      它需要排序,但在第一个重复值时退出。

      【讨论】:

      • 散列比排序快
      • 来到这里使用groupby 发布相同的解决方案并找到了这个答案。我觉得这是最优雅的,因为这是一个单一的表达式,并且可以与内置工具一起使用,不需要任何额外的变量或循环语句。
      • 如果您的列表包含不可排序的任意对象,您可以使用id() 函数对其进行排序,因为这是groupby() 工作的先决条件:groupby(sorted(seq), key=id)
      【解决方案8】:

      这是一个递归 O(N2) 版本的有趣:

      def is_unique(lst):
          if len(lst) > 1:
              return is_unique(s[1:]) and (s[0] not in s[1:])
          return True
      

      【讨论】:

        【解决方案9】:

        这是一个递归提前退出函数:

        def distinct(L):
            if len(L) == 2:
                return L[0] != L[1]
            H = L[0]
            T = L[1:]
            if (H in T):
                    return False
            else:
                    return distinct(T)    
        

        这对我来说已经足够快了,而无需使用奇怪(慢)的转换,而 采用函数式方法。

        【讨论】:

        • H in T 进行线性搜索,T = L[1:] 复制列表的切片部分,因此这将比在大列表中建议的其他解决方案慢得多。我认为是 O(N^2),而其他大多数是 O(N)(集合)或 O(N log N)(基于排序的解决方案)。
        【解决方案10】:

        这个怎么样

        def is_unique(lst):
            if not lst:
                return True
            else:
                return Counter(lst).most_common(1)[0][1]==1
        

        【讨论】:

          【解决方案11】:

          以上所有答案都很好,但我更喜欢使用30 seconds of python中的all_unique示例

          您需要在给定列表上使用set() 来删除重复项,将其长度与列表的长度进行比较。

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

          如果平面列表中的所有值都是unique,则返回True,否则返回False

          x = [1,2,3,4,5,6]
          y = [1,2,2,3,4,5]
          all_unique(x) # True
          all_unique(y) # False
          

          【讨论】:

            【解决方案12】:

            你可以使用 Yan 的语法 (len(x) > len(set(x))),但不是 set(x),而是定义一个函数:

             def f5(seq, idfun=None): 
                # order preserving
                if idfun is None:
                    def idfun(x): return x
                seen = {}
                result = []
                for item in seq:
                    marker = idfun(item)
                    # in old Python versions:
                    # if seen.has_key(marker)
                    # but in new ones:
                    if marker in seen: continue
                    seen[marker] = 1
                    result.append(item)
                return result
            

            然后执行 len(x) > len(f5(x))。这会很快,而且还能保持订单。

            那里的代码来自:http://www.peterbe.com/plog/uniqifiers-benchmark

            【讨论】:

            • 这个 f5 函数会比使用更优化速度的 set 慢。由于昂贵的“追加”操作,当列表变得非常大时,此代码开始中断。对于像x = range(1000000) + range(1000000) 这样的大型列表,运行 set(x) 比 f5(x) 快。顺序不是问题中的要求,但即使运行 sorted(set(x)) 仍然比 f5(x) 快
            【解决方案13】:

            在 Pandas 数据框中使用类似的方法来测试列的内容是否包含唯一值:

            if tempDF['var1'].size == tempDF['var1'].unique().size:
                print("Unique")
            else:
                print("Not unique")
            

            对我来说,这在包含超过一百万行的日期帧中的 int 变量上是瞬时的。

            【讨论】:

              【解决方案14】:

              它不完全适合这个问题,但如果你用谷歌搜索我让你得到的这个问题排名第一的任务,用户可能会感兴趣,因为它是问题的扩展。如果您想调查每个列表元素是否唯一,您可以执行以下操作:

              import timeit
              import numpy as np
              
              def get_unique(mylist):
                  # sort the list and keep the index
                  sort = sorted((e,i) for i,e in enumerate(mylist))
                  # check for each element if it is similar to the previous or next one    
                  isunique = [[sort[0][1],sort[0][0]!=sort[1][0]]] + \
                             [[s[1], (s[0]!=sort[i-1][0])and(s[0]!=sort[i+1][0])] 
                              for [i,s] in enumerate (sort) if (i>0) and (i<len(sort)-1) ] +\
                             [[sort[-1][1],sort[-1][0]!=sort[-2][0]]]     
                  # sort indices and booleans and return only the boolean
                  return [a[1] for a in sorted(isunique)]
              
              
              def get_unique_using_count(mylist):
                   return [mylist.count(item)==1 for item in mylist]
              
              mylist = list(np.random.randint(0,10,10))
              %timeit for x in range(10): get_unique(mylist)
              %timeit for x in range(10): get_unique_using_count(mylist)
              
              mylist = list(np.random.randint(0,1000,1000))
              %timeit for x in range(10): get_unique(mylist)
              %timeit for x in range(10): get_unique_using_count(mylist)
              

              对于一些答案中建议的get_unique_using_count 的简短列表,速度很快。但是,如果您的列表已经超过 100 个元素,则 count 函数需要很长时间。因此,get_unique 函数中显示的方法虽然看起来更复杂,但速度要快得多。

              【讨论】:

                【解决方案15】:

                对于初学者:

                def AllDifferent(s):
                    for i in range(len(s)):
                        for i2 in range(len(s)):
                            if i != i2:
                                if s[i] == s[i2]:
                                    return False
                    return True
                

                【讨论】:

                • 我喜欢这个答案,只是因为它很好地展示了使用集合时无需编写的代码。我不会给它贴上“适合初学者”的标签,因为我相信初学者应该先学会以正确的方式去做;但我遇到了一些没有经验的开发人员,他们习惯于用其他语言编写此类代码。
                猜你喜欢
                • 1970-01-01
                • 2020-04-28
                • 2019-12-22
                • 2011-04-20
                • 2018-04-24
                • 1970-01-01
                • 1970-01-01
                • 2012-10-26
                • 1970-01-01
                相关资源
                最近更新 更多