Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 最快列表索引搜索_Python_Performance_Search - Fatal编程技术网

Python 最快列表索引搜索

Python 最快列表索引搜索,python,performance,search,Python,Performance,Search,在整数列表中查找元素索引的最快方法是什么 现在我在做什么 if value in mylist: return mylist.index(value) 但我似乎做了两次同样的事情:为了知道value是否在mylist中,我还知道索引位置。我还尝试了其他解决方案: try: return mylist.index(value) except ValueError: return None 或 但所有这些解决方案似乎都比较慢 数组没有排序,只有4个元素。由于只有4个项目,

在整数列表中查找元素索引的最快方法是什么

现在我在做什么

if value in mylist:
    return mylist.index(value)
但我似乎做了两次同样的事情:为了知道
value
是否在
mylist
中,我还知道索引位置。我还尝试了其他解决方案:

try:
    return mylist.index(value)
except ValueError:
    return None

但所有这些解决方案似乎都比较慢


数组没有排序,只有4个元素。

由于只有4个项目,您也可以尝试以下操作:

 if value == mylist[0]:
   return 0
 elif value == mylist[1]:
   return 1
 elif value == mylist[2]:
   return 2
 elif value == mylist [3]:
   return 3

让我知道它在你的情况下是如何工作的。我很好奇

您可以使用集合来检查成员资格,这将比检查列表更有效,但最大的开销是索引:

In [54]: l = [1,2,3,4]

In [55]: s = set([1,2,3,4])

In [56]: timeit l.index(6)  if 6 in s else False
10000000 loops, best of 3: 79.9 ns per loop

In [57]: timeit l.index(6)  if 6 in l else False
10000000 loops, best of 3: 141 ns per loop

In [58]: timeit l.index(4)  if 4 in l else False

1000000 loops, best of 3: 381 ns per loop

In [59]: timeit l.index(4)  if 4 in s else False
1000000 loops, best of 3: 333 ns per loop

仅使用if-elses是快速的,但是如果您总是在同一个列表上搜索(或者您的列表不会经常更改),则可以通过将元素->索引映射存储在dict中,然后执行字典查找来加快搜索速度

因此,您的代码应该如下所示:

# Precompute the mapping.
mapping = { index: value for value, index in enumerate(TEST_LIST) }

# Search function:
def lookup(value):
  return mapping.get(value, None)
我运行了一些测试,将其与其他方法进行比较。以下是我的测试代码:

import timeit

TEST_LIST = [100, -2, 10007, 2**70 + 1]
mapping = { index: value for value, index in enumerate(TEST_LIST) }
NUM_TIMES = 10**6


def by_if_else(lst, value):
  if lst[0] == value:
    return 0
  elif lst[1] == value:
    return 1
  elif lst[2] == value:
    return 2
  elif lst[3] == value:
    return 3
  else:
    return None


def by_index(lst, value):
  for i in xrange(4):
    if lst[i] == value:
      return i
  return None


def by_exception(lst, value):
  try:
    lst.index(value)
  except ValueError:
    return None


def by_iter(lst, value):
  for index, element in enumerate(lst):
    if element == value:
      return value
  return None

def by_dict(lst, value):
  return mapping.get(value, None)


def TimeFunction(function_name, value):
  if 'dict' in function_name:
    return timeit.timeit(
        stmt = '%s(mapping, %d)' % (function_name, value),
        setup = 'from __main__ import %s, mapping' % function_name,
        number=NUM_TIMES)
  else:
    return timeit.timeit(
        stmt = '%s(TEST_LIST, %d)' % (function_name, value),
        setup = 'from __main__ import %s, TEST_LIST' % function_name,
        number=NUM_TIMES)


def RunTestsOn(value):
  print "Looking for %d in %s" % (value, str(TEST_LIST))
  function_names = [name for name in globals() if name.startswith('by_')]
  for function_name in function_names:
    print "Function: %s\nTime: %f" % (
        function_name, TimeFunction(function_name, value))



def main():
  values_to_look_for = TEST_LIST + [ -10**70 - 1, 55, 29]
  for value in values_to_look_for:
    RunTestsOn(value)


if __name__ == '__main__':
  main()
当搜索的值很小并且出现在列表中时(我删除了其他函数的运行时),if-else方法看起来更快:

但如果值较大(即比较昂贵),则速度较慢:

或者,当该值根本不在列表中时(即使该值很小):


很明显,使用dict应该更快,因为对于所有其他方法,dict的查询都是O(1),而不是O(n),对于如此小的列表,解释器可能正在为if-else版本创建优化的字节码,并通过哈希表执行指针跟踪的开销抵消了dict的许多速度优势。但在大多数情况下,它似乎仍然略快一些。我建议您在您的数据上测试这种方法,看看哪种方法更适合您。

老实说,这在我看来是一种过早的优化,为什么您如此担心4个要素的加速?只需选择最具可读性的语法,然后继续。你是对的,这似乎是一个过早的优化。但事实并非如此。这是我的代码的内部循环,探查器告诉我这是执行次数最多的函数。我提出了一个精确的问题,请只回答它,我没有问你是否认为它有用。一定是因为设置
try…的堆栈的开销,除了…
变量<代码>尝试…除了…在我的测试中,当我在
mylist
中有1000个元素时速度更快,但当我有4个元素时速度较慢,正如您报告的那样。但是,优化器必须与此交互:如果我将搜索操作(包括
try
块)放入函数中,我只会复制您的问题;如果我将
try
块放在我的主循环中,它会再次变快(但遗憾的是,只比mylist变量中的
if值稍微快一点)。在try/except情况下,性能完全不同,这取决于是否引发异常。构建异常非常昂贵。在for的例子中,循环的每个步骤都有很多变量查找。对于小列表,我并不惊讶你的第一个选择是最好的。顺便问一下:我的第一个解决方案是做同样的事情两次,对吗?有没有办法避免这种情况?我想你是赢家。您的解决方案比Padraic的解决方案快25%。循环展开可能是最好的解决方案。一个问题的地狱般答案。:)
import timeit

TEST_LIST = [100, -2, 10007, 2**70 + 1]
mapping = { index: value for value, index in enumerate(TEST_LIST) }
NUM_TIMES = 10**6


def by_if_else(lst, value):
  if lst[0] == value:
    return 0
  elif lst[1] == value:
    return 1
  elif lst[2] == value:
    return 2
  elif lst[3] == value:
    return 3
  else:
    return None


def by_index(lst, value):
  for i in xrange(4):
    if lst[i] == value:
      return i
  return None


def by_exception(lst, value):
  try:
    lst.index(value)
  except ValueError:
    return None


def by_iter(lst, value):
  for index, element in enumerate(lst):
    if element == value:
      return value
  return None

def by_dict(lst, value):
  return mapping.get(value, None)


def TimeFunction(function_name, value):
  if 'dict' in function_name:
    return timeit.timeit(
        stmt = '%s(mapping, %d)' % (function_name, value),
        setup = 'from __main__ import %s, mapping' % function_name,
        number=NUM_TIMES)
  else:
    return timeit.timeit(
        stmt = '%s(TEST_LIST, %d)' % (function_name, value),
        setup = 'from __main__ import %s, TEST_LIST' % function_name,
        number=NUM_TIMES)


def RunTestsOn(value):
  print "Looking for %d in %s" % (value, str(TEST_LIST))
  function_names = [name for name in globals() if name.startswith('by_')]
  for function_name in function_names:
    print "Function: %s\nTime: %f" % (
        function_name, TimeFunction(function_name, value))



def main():
  values_to_look_for = TEST_LIST + [ -10**70 - 1, 55, 29]
  for value in values_to_look_for:
    RunTestsOn(value)


if __name__ == '__main__':
  main()
Looking for 10007 in [100, -2, 10007, 1180591620717411303425L]
Function: by_dict
Time: 0.213232
Function: by_if_else
Time: 0.181917
Looking for 1180591620717411303425 in [100, -2, 10007, 1180591620717411303425L]
Function: by_dict
Time: 0.223594
Function: by_if_else
Time: 0.380222
Looking for 29 in [100, -2, 10007, 1180591620717411303425L]
Function: by_dict
Time: 0.195733
Function: by_if_else
Time: 0.267689