Самый быстрый способ проверить, существует ли значение в списке

Какой самый быстрый способ узнать, существует ли значение в списке (список с миллионами значений в нем) и каков его индекс?

Я знаю, что все значения в списке уникальны, как в этом примере.

Первый метод, который я пробую, - это (3,8 сек в моем реальном коде):

a = [4,2,3,1,5,6]

if a.count(7) == 1:
    b=a.index(7)
    "Do something with variable b"

Второй метод, который я пытаюсь использовать (в 2 раза быстрее: 1,9 с для моего реального кода):

a = [4,2,3,1,5,6]

try:
    b=a.index(7)
except ValueError:
    "Do nothing"
else:
    "Do something with variable b"

Предлагаемые методы от пользователя (2,74 с для моего реального кода):

a = [4,2,3,1,5,6]
if 7 in a:
    a.index(7)

В моем реальном коде первый метод занимает 3,81 секунды, а второй - 1,88 секунды. Это хорошее улучшение, но:

Я новичок в Python/scripting, и есть ли более быстрый способ сделать то же самое и сэкономить больше времени на обработку?

Более конкретное объяснение для моего приложения:

В Blender API я могу получить доступ к списку частиц:

particles = [1, 2, 3, 4, etc.]

Оттуда я могу получить доступ к местоположению частицы:

particles[x].location = [x,y,z]

И для каждой частицы я проверяю, существует ли сосед, выполняя поиск каждой локации частицы следующим образом:

if [x+1,y,z] in particles.location
    "Find the identity of this neighbour particle in x:the particle index
    in the array"
    particles.index([x+1,y,z])

Ответ 1

7 in a

Самый простой и быстрый способ сделать это.

Вы также можете рассмотреть возможность использования set, но для построения этого набора из вашего списка может потребоваться больше времени, чем ускорение тестирования членства. Единственный способ быть уверенным в том, чтобы хорошо ориентироваться. (это также зависит от того, какие операции вам требуются)

Ответ 2

Как заявляют другие, in больших списках может быть очень медленно. Вот несколько сравнений характеристик для in, set и bisect. Обратите внимание, что время (во втором) находится в шкале журнала.

enter image description here

Код для тестирования:

import random
import bisect
import matplotlib.pyplot as plt
import math
import time

def method_in(a,b,c):
    start_time = time.time()
    for i,x in enumerate(a):
        if x in b:
            c[i] = 1
    return(time.time()-start_time)   

def method_set_in(a,b,c):
    start_time = time.time()
    s = set(b)
    for i,x in enumerate(a):
        if x in s:
            c[i] = 1
    return(time.time()-start_time)

def method_bisect(a,b,c):
    start_time = time.time()
    b.sort()
    for i,x in enumerate(a):
        index = bisect.bisect_left(b,x)
        if index < len(a):
            if x == b[index]:
                c[i] = 1
    return(time.time()-start_time)

def profile():
    time_method_in = []
    time_method_set_in = []
    time_method_bisect = []

    Nls = [x for x in range(1000,20000,1000)]
    for N in Nls:
        a = [x for x in range(0,N)]
        random.shuffle(a)
        b = [x for x in range(0,N)]
        random.shuffle(b)
        c = [0 for x in range(0,N)]

        time_method_in.append(math.log(method_in(a,b,c)))
        time_method_set_in.append(math.log(method_set_in(a,b,c)))
        time_method_bisect.append(math.log(method_bisect(a,b,c)))

    plt.plot(Nls,time_method_in,marker='o',color='r',linestyle='-',label='in')
    plt.plot(Nls,time_method_set_in,marker='o',color='b',linestyle='-',label='set')
    plt.plot(Nls,time_method_bisect,marker='o',color='g',linestyle='-',label='bisect')
    plt.xlabel('list size', fontsize=18)
    plt.ylabel('log(time)', fontsize=18)
    plt.legend(loc = 'upper left')
    plt.show()

Ответ 3

Вы можете поместить свои предметы в set. Набор запросов очень эффективен.

Пытаться:

s = set(a)
if 7 in s:
  # do stuff

edit В комментарии вы говорите, что хотите получить индекс элемента. К сожалению, наборы не имеют понятия о позиции элемента. Альтернативой является предварительная сортировка списка, а затем использование бинарного поиска каждый раз, когда вам нужно найти элемент.

Ответ 4

def check_availability(element, collection: iter):
    return element in collection

использование

check_availability('a', [1,2,3,4,'a','b','c'])

Я считаю, что это самый быстрый способ узнать, есть ли выбранное значение в массиве.

Ответ 5

a = [4,2,3,1,5,6]

index = dict((y,x) for x,y in enumerate(a))
try:
   a_index = index[7]
except KeyError:
   print "Not found"
else:
   print "found"

Это будет хорошей идеей, если a не изменится, и поэтому мы можем сделать часть dict() один раз, а затем использовать ее повторно. Если это действительно так, пожалуйста, предоставьте более подробную информацию о том, что вы делаете.

Ответ 6

Похоже, ваше приложение может получить выгоду от использования структуры данных Bloom Filter.

Короче говоря, просмотр фильтра цветения может рассказать вам очень быстро, если значение ОПРЕДЕЛЕННО НЕ присутствует в наборе. В противном случае вы можете сделать более медленный поиск, чтобы получить индекс значения, которое ВОЗМОЖНО МОЖЕТ БЫТЬ в списке. Поэтому, если ваше приложение имеет тенденцию получать результат "не найден" гораздо чаще, чем "найденный" результат, вы можете увидеть ускорение, добавив Bloom Filter.

Подробнее см. в Википедии, в котором содержится хороший обзор того, как работают Bloom Filters, и веб-поиск "библиотеки фильтров цветения python" предоставит по крайней мере пару полезных реализаций.

Ответ 7

Имейте в виду, что in тестах оператор не только равенство (==), но и идентичность (is), то in логике для list является примерно эквивалентно следующему (она написана на C, а не Python, хотя, по крайней мере, в CPython):

for element in s:
    if element is target:
        # fast check for identity implies equality
        return True
    if element == target:
        # slower check for actual equality
        return True
return False

В большинстве случаев эта деталь не имеет значения, но в некоторых случаях это может привести к тому, что начинающий Python удивит, например, numpy.NAN имеет необычное свойство быть не равным себе:

>>> import numpy
>>> numpy.NAN == numpy.NAN
False
>>> numpy.NAN is numpy.NAN
True
>>> numpy.NAN in [numpy.NAN]
True

Чтобы различать эти необычные случаи, вы можете использовать any():

>>> lst = [numpy.NAN, 1 , 2]
>>> any(element == numpy.NAN for element in lst)
False
>>> any(element is numpy.NAN for element in lst)
True 

Обратите внимание, что in логике для list с any() будет:

any(element is target or element == target for element in lst)

Тем не менее, я должен подчеркнуть, что это крайний случай, и для подавляющего большинства случаев in операторе оптимизированный и именно то, что вы хотите, конечно (или с list или с set).

Ответ 8

Или используйте __contains__:

sequence.__contains__(value)

Демо - версия:

>>> l=[1,2,3]
>>> l.__contains__(3)
True
>>> 

Ответ 9

Это не код, а алгоритм очень быстрого поиска.

Если ваш список и значение, которое вы ищете, все числа, это довольно просто. Если строки: посмотрите внизу:

  • -Let "n" - длина вашего списка
  • -Optional шаг: если вам нужен индекс элемента: добавьте второй список в список с текущим индексом элементов (от 0 до n-1) - см. Позже
  • Заказать свой список или его копию (.sort())
  • Переберите:
    • Сравните ваш номер с п /2-м элементом списка
      • Если больше, повторите цикл между индексами n/2-n
      • Если меньше, повторите цикл между индексами 0-n/2
      • Если то же самое: вы нашли это
  • Продолжайте сужать список, пока не найдете его или не получите только 2 числа (ниже и выше того, которое вы ищете)
  • Это найдет любой элемент не более чем в 19 шагах для списка 1.000.000 (log (2) n, если быть точным)

Если вам также нужна исходная позиция вашего номера, найдите ее во втором столбце индекса.

Если ваш список не состоит из чисел, метод все еще работает и будет самым быстрым, но вам может потребоваться определить функцию, которая может сравнивать/упорядочивать строки.

Конечно, это требует вложений метода sorted(), но если вы продолжаете использовать один и тот же список для проверки, это может стоить того.

Ответ 10

present = False
searchItem = 'd'
myList = ['a', 'b', 'c', 'd', 'e']
if searchItem in myList:
   present = True
   print('present = ', present)
else:
   print('present = ', present)

Ответ 11

Решение @Winston Ewert дает большое ускорение для очень больших списков, но этот ответ на стекопоток указывает, что конструкция try: /exception: /else: будет замедлена, если часто достигается ветвь исключений. Альтернативой является использование метода .get() для dict:

a = [4,2,3,1,5,6]

index = dict((y, x) for x, y in enumerate(a))

b = index.get(7, None)
if b is not None:
    "Do something with variable b"

Метод .get(key, default) предназначен только для случая, когда вы не можете гарантировать, что ключ будет в dict. Если ключ присутствует, он возвращает значение (как было бы dict[key]), но когда его нет, .get() возвращает ваше значение по умолчанию (здесь None). Вы должны убедиться, что в этом случае, что выбранный по умолчанию не будет в. a

Ответ 12

попробовать

n =0
while n <= 7:
    list_a = ['omar','loubna','najawa','mohamed','essa','ahmed']
    x = input("Enter your name:")
    n = n+1
    if x in list_a:
        print("ok")
    if x not in list_a:
        print("ValueError: ",x, "is not in list")

Ответ 13

Для меня это было 0,030 с (реальное), 0,026 с (пользователь) и 0,004 с (sys).

try:
print("Started")
x = ["a", "b", "c", "d", "e", "f"]

i = 0

while i < len(x):
    i += 1
    if x[i] == "e":
        print("Found")
except IndexError:
    pass

Ответ 14

Код для проверки наличия двух элементов в массиве, произведение которых равно k:

n = len(arr1)
for i in arr1:
    if k%i==0:
        print(i)