Есть ли библиотечная функция, которая выполняет бинарный поиск по списку / кортежу и возвращает позицию элемента, если он найден, и «Ложь» (-1, нет и т. Д.), Если нет?
Я нашел функции bisect_left / right в модуле bisect , но они по-прежнему возвращают позицию, даже если элемент отсутствует в списке. Это прекрасно для их предполагаемого использования, но я просто хочу знать, есть ли элемент в списке или нет (не хочу ничего вставлять).
Я подумал об использовании, bisect_left
а затем проверке, равен ли элемент в этой позиции тому, что я ищу, но это кажется громоздким (и мне также нужно выполнить проверку границ, если число может быть больше, чем наибольшее число в моем списке). Если есть более хороший метод, я бы хотел узнать об этом.
Редактировать Чтобы уточнить, для чего мне это нужно: я знаю, что словарь будет очень хорошо для этого подходить, но я стараюсь максимально снизить потребление памяти. Мое предполагаемое использование было бы своего рода двусторонней справочной таблицей. У меня есть в таблице список значений, и мне нужно иметь возможность доступа к значениям на основе их индекса. А также я хочу иметь возможность найти индекс определенного значения или None, если значение отсутствует в списке.
Использование словаря для этого было бы самым быстрым способом, но (приблизительно) удвоило бы требования к памяти.
Я задавал этот вопрос, думая, что я что-то упустил из библиотек Python. Кажется, мне придется написать свой собственный код, как предложил Мо.
источник
np.searchsorted
это полезно. docs.scipy.org/doc/numpy/reference/generated/…Ответы:
источник
if hi is None: hi = len(a)
Почему бы не взглянуть на код для bisect_left / right и адаптировать его под свои цели.
как это:
источник
hi = mid - 1
вelif
?hi = mid
наhi = mid-1
иhi = len(a)
кhi = len(a)-1
иwhile lo < hi:
кwhile lo <= hi
, и это будет эквивалентно правильноbisect.bisect_left()
а не это.Это немного не по теме (поскольку ответ Мо кажется полным на вопрос ОП), но, возможно, стоит рассмотреть сложность всей вашей процедуры от начала до конца. Если вы храните вещи в отсортированных списках (где бинарный поиск может помочь), а затем просто проверяете существование, вы подвергаетесь (наихудший случай, если не указано):
Сортированные списки
Принимая во внимание
set()
, что вы несетеСортированный список действительно дает вам «следующее», «предыдущее» и «диапазоны» (включая вставку или удаление диапазонов), которые равны O (1) или O (| range |), с учетом начального индекса. Если вы не используете такие операции часто, тогда лучше хранить в виде наборов и сортировать для отображения.
set()
в питоне очень мало дополнительных накладных расходов.источник
Возможно, стоит упомянуть, что в документах bisect теперь есть примеры поиска: http://docs.python.org/library/bisect.html#searching-sorted-lists
(Повышение ValueError вместо возврата -1 или None является более питоническим - например, list.index () делает это. Но, конечно, вы можете адаптировать примеры к вашим потребностям.)
источник
Проще всего использовать bisect и проверить одну позицию назад, чтобы увидеть, есть ли там элемент:
источник
Это прямо из руководства:
http://docs.python.org/2/library/bisect.html
8.5.1. Поиск отсортированных списков
Вышеуказанные функции bisect () полезны для поиска точек вставки, но могут быть сложными или неудобными для использования в обычных задачах поиска Следующие пять функций показывают, как преобразовать их в стандартный поиск для отсортированных списков:
Так что с небольшой модификацией ваш код должен быть:
источник
Я согласен, что ответ @ DaveAbrahams с использованием модуля bisect является правильным подходом. Он не упомянул одну важную деталь в своем ответе.
Из документов
bisect.bisect_left(a, x, lo=0, hi=len(a))
Модуль деления пополам не требует предварительного вычисления массива поиска. Вы можете просто представить конечные точки
bisect.bisect_left
вместо него, используя значения по умолчанию0
иlen(a)
.Еще более важно для моего использования поиск значения X, такого, чтобы ошибка данной функции была минимизирована. Чтобы сделать это, мне нужен был способ, чтобы алгоритм bisect_left вызывал мои вычисления вместо этого. Это действительно просто.
Просто предоставьте объект, который определяет
__getitem__
какa
Например, мы могли бы использовать алгоритм bisect, чтобы найти квадратный корень с произвольной точностью!
источник
scipy.optimize
для этого.Если вы просто хотите увидеть, присутствует ли он, попробуйте превратить список в диктовку:
На моей машине «if n in l» заняло 37 секунд, а «if n in d» - 0,4 секунды.
источник
Этот:
источник
Решение Дейва Абрахамса это хорошо. Хотя я бы сделал это минималистично
источник
Хотя в Python нет явного алгоритма двоичного поиска, существует модуль,
bisect
предназначенный для поиска точки вставки элемента в отсортированном списке с помощью двоичного поиска. Это можно «обмануть» при выполнении бинарного поиска. Самым большим преимуществом этого является то же преимущество, которое имеет большинство библиотечного кода - он высокопроизводительный, хорошо протестированный и просто работает (в частности, бинарный поиск может быть довольно сложным для успешной реализации - особенно если крайние случаи не рассматриваются тщательно).Основные типы
Для базовых типов, таких как Strings или Ints, это довольно просто - все, что вам нужно, это
bisect
модуль и отсортированный список:Вы также можете использовать это, чтобы найти дубликаты:
Очевидно, что вы можете просто вернуть индекс, а не значение этого индекса, если хотите.
Объекты
Для пользовательских типов или объектов все немного сложнее: вы должны убедиться, что реализовали богатые методы сравнения, чтобы получить правильное сравнение.
Это должно работать как минимум в Python 2.7 -> 3.3
источник
Использование dict не приведет к удвоению использования вашей памяти, если только хранящиеся вами объекты не будут действительно крошечными, поскольку значения являются только указателями на реальные объекты:
В этом примере «foo» сохраняется только один раз. Это имеет значение для вас? И сколько конкретно предметов мы говорим?
источник
Этот код рекурсивно работает со списками целых чисел. Ищет простейший сценарий: длина списка меньше 2. Это означает, что ответ уже существует, и выполняется проверка для проверки правильности ответа. Если нет, то среднее значение устанавливается и проверяется на правильность, если не делится пополам, снова вызывая функцию, но устанавливая среднее значение в качестве верхнего или нижнего предела, сдвигая его влево или вправо.
источник
Проверьте примеры в Википедии http://en.wikipedia.org/wiki/Binary_search_algorithm
источник
Я думаю, это намного лучше и эффективнее. поправьте меня пожалуйста :) Спасибо
источник
s
это список.binary(s, 0, len(s) - 1, find)
это начальный звонок.Функция возвращает индекс запрашиваемого элемента. Если такого элемента нет, он возвращается
-1
.источник
источник
Бинарный поиск:
// Для вызова вышеуказанной функции используйте:
источник
Мне нужен бинарный поиск в Python и общий для моделей Django. В моделях Django одна модель может иметь внешний ключ к другой модели, и я хотел выполнить некоторый поиск по найденным объектам моделей. Я написал следующую функцию, вы можете использовать это.
источник
Выше было много хороших решений, но я не видел простого (KISS делает его простым (потому что я)) глупого использования встроенной функции Python / generic bisect для выполнения бинарного поиска. С небольшим количеством кода вокруг функции bisect, Я думаю, что у меня есть пример ниже, где я проверил все случаи для небольшого строкового массива имен.Некоторые из приведенных выше решений ссылаются на / говорят это, но, надеюсь, простой код ниже поможет любому запутаться, как я.
Python bisect используется, чтобы указать, куда вставить новое значение / элемент поиска в отсортированный список. Приведенный ниже код, который использует bisect_left, который будет возвращать индекс попадания, если найден элемент поиска в списке / массиве (обратите внимание, что bisect и bisect_right вернут индекс элемента после попадания или совпадения в качестве точки вставки) Если не найден , bisect_left вернет индекс к следующему элементу в отсортированном списке, который не = = значение поиска. Единственный другой случай - это когда элемент поиска будет находиться в конце списка, где возвращаемый индекс будет за концом списка / массива, и в коде ниже раннего выхода из Python с помощью «и» логических дескрипторов. (первое условие False Python не проверяет последующие условия)
источник