Самый быстрый способ проверить, существует ли значение в списке
Какой самый быстрый способ проверить, существует ли значение в очень большом списке (с миллионами значений) и каков его индекс?
Переведено автоматически
Ответ 1
7in a
Самый простой и быстрый способ сделать это.
Вы также можете рассмотреть возможность использования set, но создание этого набора из вашего списка может занять больше времени, чем сэкономит более быстрое тестирование членства. Единственный способ убедиться в этом - хорошо протестировать. (это также зависит от того, какие операции вам требуются)
Ответ 2
Как указывали другие, in может быть очень медленным для больших списков. Вот несколько сравнений производительности для in, set и bisect. Обратите внимание, что время (в секундах) указано в логарифмическом масштабе.
Код для тестирования:
import random import bisect import matplotlib.pyplot as plt import math import time
defmethod_in(a, b, c): start_time = time.time() for i, x inenumerate(a): if x in b: c[i] = 1 return time.time() - start_time
defmethod_set_in(a, b, c): start_time = time.time() s = set(b) for i, x inenumerate(a): if x in s: c[i] = 1 return time.time() - start_time
defmethod_bisect(a, b, c): start_time = time.time() b.sort() for i, x inenumerate(a): index = bisect.bisect_left(b, x) if index < len(a): if x == b[index]: c[i] = 1 return time.time() - start_time
# adjust range down if runtime is too long or up if there are too many zero entries in any of the time_method lists Nls = [x for x inrange(10000, 30000, 1000)] for N in Nls: a = [x for x inrange(0, N)] random.shuffle(a) b = [x for x inrange(0, N)] random.shuffle(b) c = [0for x inrange(0, N)]
Вы могли бы поместить свои элементы в set. Поиск по настройкам очень эффективен.
Попробуйте:
s = set(a) if7in s: # do stuff
редактировать В комментарии вы говорите, что хотели бы получить индекс элемента. К сожалению, наборы не имеют представления о позиции элемента. Альтернативой является предварительная сортировка вашего списка, а затем использование бинарного поиска каждый раз, когда вам нужно найти элемент.
Ответ 4
Первоначальный вопрос был:
Какой самый быстрый способ узнать, существует ли значение в списке (списке с миллионами значений в нем) и каков его индекс?
Таким образом, нужно найти две вещи:
это элемент в списке, и
что такое индекс (если в списке).
Для этого я модифицировал код @xslittlegrass для вычисления индексов во всех случаях и добавил дополнительный метод.
Результаты
Методы:
в--в основном, если x в b: возвращает b.index(x)
попробуйте--try / catch для b.index(x) (не нужно проверять, есть ли x в b)
set - в основном, если x в set(b): возвращает b.index(x)
разделить пополам - отсортировать b по его индексу, двоичный поиск x в sorted(b). Обратите внимание на мод от @xslittlegrass, который возвращает индекс в отсортированном b, а не исходном b)
reverse- сформировать словарь обратного поиска d для b; затем d [x] предоставляет индекс x.
Результаты показывают, что метод 5 является самым быстрым.
Интересно, что методы try и set эквивалентны по времени.
Тестовый код
import random import bisect import matplotlib.pyplot as plt import math import timeit import itertools
defwrapper(func, *args, **kwargs): " Use to produced 0 argument function for call it" # Reference https://www.pythoncentral.io/time-a-python-function/ defwrapped(): return func(*args, **kwargs) return wrapped
defmethod_in(a,b,c): for i,x inenumerate(a): if x in b: c[i] = b.index(x) else: c[i] = -1 return c
defmethod_try(a,b,c): for i, x inenumerate(a): try: c[i] = b.index(x) except ValueError: c[i] = -1
defmethod_set_in(a,b,c): s = set(b) for i,x inenumerate(a): if x in s: c[i] = b.index(x) else: c[i] = -1 return c
defmethod_bisect(a,b,c): " Finds indexes using bisection "
# Create a sorted b with its index bsorted = sorted([(x, i) for i, x inenumerate(b)], key = lambda t: t[0])
for i,x inenumerate(a): index = bisect.bisect_left(bsorted,(x, )) c[i] = -1 if index < len(a): if x == bsorted[index][0]: c[i] = bsorted[index][1] # index in the b array
return c
defmethod_reverse_lookup(a, b, c): reverse_lookup = {x:i for i, x inenumerate(b)} for i, x inenumerate(a): c[i] = reverse_lookup.get(x, -1) return c
defprofile(): Nls = [x for x inrange(1000,20000,1000)] number_iterations = 10 methods = [method_in, method_try, method_set_in, method_bisect, method_reverse_lookup] time_methods = [[] for _ inrange(len(methods))]
for N in Nls: a = [x for x inrange(0,N)] random.shuffle(a) b = [x for x inrange(0,N)] random.shuffle(b) c = [0for x inrange(0,N)]
for i, func inenumerate(methods): wrapped = wrapper(func, a, b, c) time_methods[i].append(math.log(timeit.timeit(wrapped, number=number_iterations)))