【问题标题】:What is the fastes way to find an item in a list in python?在 python 列表中查找项目的最快方法是什么?
【发布时间】:2021-07-17 19:24:32
【问题描述】:

对于我的项目,我需要在列表中反复查找时间戳的索引,以及是否准确的时间戳 不在列表中我需要在我要查找的时间戳之前找到时间戳的索引。 我尝试遍历列表,但这很慢:

def find_item_index(arr, x):
    '''
    returns index of x in ordered list.
    If x is between two items in the list, the index of the lower one is returned.
    '''

    for index in range(len(arr)):
        if arr[index] <= x < arr[index+1]:
            return index

    raise ValueError(f'{x} not in array.')

我也尝试过递归,但速度更慢:

def find_item_index_recursive(arr, x, index = 0):
    '''
    returns index of x in ordered list.
    If x is between two items in the list, the index of the lower one is returned.
    '''

    length = len(arr)

    if length == 1:
        return index

    if arr[length // 2] < x:
        return find_item_index_recursive(arr[length // 2:], x, index + length // 2)
    else:
        return find_item_index_recursive(arr[:length // 2], x, index)

    raise ValueError(f'{x} not in array.')

有更快的方法吗?

【问题讨论】:

  • 递归方法很慢,因为您通过切片制作了大量副本。将开始/结束索引与原始列表一起传递,它应该很快。
  • 排序并使用bisect!
  • 排序肯定比在列表中循环一个循环要慢@ti7
  • 这能回答你的问题吗? Fastest way to find Indexes of item in list?
  • @PranavHosangadi 肯定是,但他们需要重复找到一些东西并暗示列表已排序(否则为什么索引很重要?)

标签: python list performance recursion search


【解决方案1】:

对列表进行排序并在对其进行任何操作之前跟踪它是否已排序

if not arr_is_sorted:     # create me somewhere!
    arr.sort()            # inplace sort
    arr_is_sorted = True  # unset if you're unsure if the array is sorted

使用排序列表,您可以通过binary search 高效地O(log n) 找到插入点 - 有一个方便的内置库,bisect

import bisect
insertion_point = bisect.bisect_left(arr, x)

这也使数组保持排序,因此除非您对其进行不相关的更改,否则您无需重新排序(理想情况下,您永远不会进行无序插入,因此它将始终排序)

这里有一个完整的例子来说明如何使用 bisect

>>> l = [100,50,200,99]
>>> l.sort()
>>> l
[50, 99, 100, 200]
>>> import bisect
>>> bisect.bisect_left(l, 55)
1
>>> bisect.bisect_left(l, 201)
4

您可以使用arr.insert(position, value) 将值放入列表中

>>> l
[50, 99, 100, 200]
>>> value = 55
>>> l.insert(bisect.bisect_left(l, value), value)
>>> l
[50, 55, 99, 100, 200]

您可以通过检查该位置是否已经相等来防止重复插入

>>> pos = bisect.bisect_left(l, value)
>>> if pos == len(l) or l[pos] != value:  # length check avoids IndexError
...     l.insert(pos, value)

【讨论】:

    【解决方案2】:

    Numpy searchsorted 通常涉及这些情况:

    np.searchsorted([1,2,8,9], 5) # Your case
    > 2
    
    np.searchsorted([1,2,8,9], (-1, 2, 100))  #Other cases
    > array([0, 1, 4])
    

    缺失案例中的索引指的是近右。如果这不是您的情况,可以对其进行修改以获得靠近左侧的位置。

    【讨论】:

      【解决方案3】:

      我认为这应该很快工作: (我假设您的时间戳已排序?)

      def find_item_index(arr, x):
          '''
          returns index of x in ordered list.
          If x is between two items in the list, the index of the lower one is returned.
          '''
          
          l = len(arr)
          i = l//2
          j = i//2
          
          while(j>0):
              if x<arr[i]:
                  i-= j
              else:
                  i+= j
              j = j//2
          return i
      

      编辑:我刚刚检查过。与您的第一个版本相比,更长的列表更快。我预计至少 4 倍,如果列表变得更长甚至 10 倍

      【讨论】:

        【解决方案4】:

        List 有一个内置方法,可以为您提供元素的索引。如果未找到该元素,则会引发 value 错误。

        try:
            index = list1.index(element_to_search)
        except ValueError as e:
            print('element not found')
        

        【讨论】:

        • 这有帮助,如果确切的项目在数组中,但如果我要查找的项目位于数组的两个条目之间,则无济于事。
        猜你喜欢
        • 1970-01-01
        • 2011-01-05
        • 2016-06-09
        • 2017-05-11
        • 2020-12-15
        • 2021-03-23
        • 1970-01-01
        • 1970-01-01
        • 2012-05-20
        相关资源
        最近更新 更多