Как найти индекс, по которому новый элемент можно вставить в отсортированный список, и сохранить его отсортированным?

a = 132

b = [0, 10, 30, 60, 100, 150, 210, 280, 340, 480, 530]

Я хочу знать, что a должен быть на 6-й позиции в упорядоченном списке b.

Какой самый пифонический способ сделать это?


person est    schedule 02.07.2012    source источник
comment
a на самом деле будет на 6-й позиции в b, а не на 4-й. И, как заметил @madjar, использовал модуль bisect. bisect.bisect(b, a) для получения позиции (или bisect_[left|right]) и для вставки bisect.insort(b, a) или insort[left|right].   -  person Christian Witts    schedule 02.07.2012


Ответы (3)


Используйте деление пополам. Это не самый красивый API, но именно то, что вам нужно.

Вы захотите использовать bisect.bisect, который возвращает именно то, что вы хотите.

person madjar    schedule 02.07.2012
comment
Почему это не самый красивый API? - person Tanmay; 29.07.2016

bisect — это модуль в стандартной библиотеке Python, который идеально подходит для этой задачи. Функция bisect в модуле bisect даст вам индекс точки вставки значения.

Позвольте мне привести пример кода для bisect

from bisect import bisect
a = 132
b = [0, 10, 30, 60, 100, 150, 210, 280, 340, 480, 530]
print(bisect(b, a))

Результат будет 5, потому что список начинается с 0, так что на самом деле это 6-я позиция.

Что вы можете знать, так это использовать результат для insert.

index = bisect(b, a)
b.insert(index, a)

или без промежуточной переменной

b.insert(bisect(b, a), a)

Теперь b будет [0, 10, 30, 60, 100, 132, 150, 210, 280, 340, 480, 530].

person Matthias    schedule 02.07.2012
comment
что, если a — это объект или словарь, а b — отсортированный список объектов или словарь? - person Nwawel A Iroume; 01.02.2020

Есть еще одна проблема с пограничными случаями. Например, предположим, что вы хотите выбрать элементы в вышеупомянутом b в диапазоне (a, c) и выбираете их с помощью

b[idx_a:idx_c]

тогда вам нужно подумать о случае, когда a, c на самом деле являются элементами b. Обратите внимание, что

bisect.bisect(b, 10)
bisect.bisect(b, 11)

обе дадут индекс 2. Таким образом, если a=10 нам нужно понизить индекс на 1. К счастью, есть функция bisect.bisect_left, которая делает именно это, т.е. в нашем примере

bisect.bisect_left(b, 10)

дает 1.

В целом, левый индекс должен быть рассчитан с использованием bisect.bisect_left() и правого индекса bisect.bisect_right() (что совпадает с bisect.bisect()).

person nos    schedule 18.07.2017