【问题标题】:What is the best possible way to find the first AND the last occurrences of an element in a list in Python?在 Python 的列表中查找第一个和最后一个元素的最佳方法是什么?
【发布时间】:2020-12-23 09:49:05
【问题描述】:

我通常使用的基本方法是使用 list.index(element) 和 reversed_list.index(element),但是当我需要搜索很多元素并且列表的长度太大比如 10^ 时,这会失败5 或者说 10^6 甚至更大。最好的方法是什么(使用很少的时间)?

【问题讨论】:

    标签: python-3.x list find-occurrences


    【解决方案1】:

    您可以构建辅助查找结构:

    lst = [1,2,3,1,2,3] # super long list
    
    last = {n: i for i, n in enumerate(lst)}
    first = {n: i for i, n in reversed(list(enumerate(lst)))}
    last[3]
    # 5
    first[3]
    # 2
    

    查找字典的构建需要线性时间,但查找本身是恒定的。 Wreas 调用 list.index() 需要线性时间,然后重复这样做是二次的(鉴于您进行的查找次数取决于列表的大小)。

    您也可以在一次迭代中构建单个结构:

    from collections import defaultdict
    
    lookup = defaultdict(lambda: [None, None])
    
    for i, n in enumerate(lst):
        lookup[n][1] = i
        if lookup[n][0] is None:
            lookup[n][0] = i
        
    
    lookup[3]
    # [2, 5]
    lookup[2]
    # [1, 4]
    

    【讨论】:

      【解决方案2】:

      嗯,需要有人来寻找元素,而在一个大列表中,这可能需要时间!如果没有更多信息或代码示例,将很难为您提供帮助,但通常首选的答案是使用另一种数据结构 - 例如,如果您可以将元素保存在字典中而不是带有键的列表中作为元素和值是一个索引数组,你会快得多。

      【讨论】:

      • 我忘记使用字典了。为第一个和最后一个索引分别制作两个字典。谢谢!
      【解决方案3】:

      您只需记住列表中每个元素的第一个和最后一个索引:

      In [9]: l = [random.randint(1, 10) for _ in range(100)]
      
      In [10]: first_index = {}
      
      In [11]: last_index = {}
      
      In [12]: for idx, x in enumerate(l):
          ...:     if x not in first_index:
          ...:         first_index[x] = idx
          ...:     last_index[x] = idx
          ...:
      
      
      In [13]: [(x, first_index.get(x), last_index.get(x)) for x in range(1, 11)]
      Out[13]:
      [(1, 3, 88),
       (2, 23, 90),
       (3, 10, 91),
       (4, 13, 98),
       (5, 11, 57),
       (6, 4, 99),
       (7, 9, 92),
       (8, 19, 95),
       (9, 0, 77),
       (10, 2, 87)]
      
      In [14]: l[0]
      Out[14]: 9
      

      【讨论】:

      • 对不起,但我不明白这段代码的作用(我要求在一个非常长的列表中搜索大量元素)。正如@maor10 指出的那样,为第一个和最后一个索引制作两个字典是可行的。谢谢!
      【解决方案4】:

      你的方法听起来不错,我做了一些测试:

      import numpy as np
      
      long_list = list(np.random.randint(0, 100_000, 100_000_000))
      
      # This takes 10ms in my machine
      long_list.index(999)
      
      # This takes 1,100ms in my machine
      long_list[::-1].index(999)
      
      # This takes 1,300ms in my machine
      list(reversed(long_list)).index(999)
      
      # This takes 200ms in my machine
      long_list.reverse()
      long_list.index(999)
      long_list.reverse()
      

      但归根结底,Python 列表似乎并不是最好的数据结构。

      按照其他人的建议,您可以构建一个字典:

      indexes = {}
      for i, val in enumerate(long_list):
          if val in indexes.keys():
              indexes[val].append(i)
          else:
              indexes[val] = [i]
      

      这很消耗内存,但可以解决您的问题(取决于您修改原始列表的频率)。

      你可以这样做:

      # This takes 0.02ms in my machine
      ix = indexes.get(999)
      ix[0], ix[-1]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-09
        • 2020-12-18
        • 2012-02-02
        • 2012-06-11
        • 1970-01-01
        • 2018-08-15
        • 1970-01-01
        相关资源
        最近更新 更多