Если L отсортирован, можно использовать bisect.bisect_left
найти индекс, для которых все L [< я] < < п = все L [> = я].
Тогда
if n - L[i-1] < 1.0:
val = L[i-1]
elif L[i] - n < 1.0:
val = L[i]
else:
val = None # no such value found
Edit: В зависимости от ваших данных, что вы хотите достичь, и сколько времени вы хотите провести писать умный алгоритм, сортировочные могут быть или не быть хорошим решением для вас; и, прежде чем я увижу слишком много O (n) s, развернутых вокруг, я хотел бы указать, что его фактическая проблема, по-видимому, связана с неоднократным исследованием для различных значений n - что бы довольно быстро амортизировать начальные накладные расходы на сортировку - и что его предложение Алгоритм выше - фактически O (n ** 2).
@AntoinePelisse: все средства, давайте делать некоторое профилирование:
from bisect import bisect_left, bisect_right
from functools import partial
import matplotlib.pyplot as plt
from random import randint, uniform
from timeit import timeit
#blues
density_col_lin = [
(0.000, 0.502, 0.000, 1.000),
(0.176, 0.176, 0.600, 1.000),
(0.357, 0.357, 0.698, 1.000),
(0.537, 0.537, 0.800, 1.000)
]
# greens
density_col_sor = [
(0.000, 0.502, 0.000, 1.000),
(0.176, 0.600, 0.176, 1.000),
(0.357, 0.698, 0.357, 1.000),
(0.537, 0.800, 0.537, 1.000)
]
def make_data(length, density):
max_ = length/density
return [uniform(0.0, max_) for _ in range(length)], max_
def linear_probe(L, max_, probes):
for p in range(probes):
n = randint(0, int(max_))
for index,val in enumerate(L):
if n - 1.0 < val < n + 1.0:
# return index
break
def sorted_probe(L, max_, probes):
# initial sort
sL = sorted((val,index) for index,val in enumerate(L))
for p in range(probes):
n = randint(0, int(max_))
left = bisect_right(sL, (n - 1.0, max_))
right = bisect_left (sL, (n + 1.0, 0.0), left)
if left < right:
index = min(sL[left:right], key=lambda s:s[1])[1]
# return index
def main():
densities = [0.8, 0.2, 0.08, 0.02]
probes = [1, 3, 10, 30, 100]
lengths = [[] for d in densities]
lin_pts = [[[] for p in probes] for d in densities]
sor_pts = [[[] for p in probes] for d in densities]
# time each function at various data lengths, densities, and probe repetitions
for d,density in enumerate(densities):
for trial in range(200):
print("{}-{}".format(density, trial))
# length in 10 to 5000, with log density
length = int(10 ** uniform(1.0, 3.699))
L, max_ = make_data(length, density)
lengths[d].append(length)
for p,probe in enumerate(probes):
lin = timeit(partial(linear_probe, L, max_, probe), number=5)/5
sor = timeit(partial(sorted_probe, L, max_, probe), number=5)/5
lin_pts[d][p].append(lin/probe)
sor_pts[d][p].append(sor/probe)
# plot the results
plt.figure(figsize=(9.,6.))
plt.axis([0, 5000, 0, 0.004])
for d,density in enumerate(densities):
xs = lengths[d]
lcol = density_col_lin[d]
scol = density_col_sor[d]
for p,probe in enumerate(probes):
plt.plot(xs, lin_pts[d][p], "o", color=lcol, markersize=4.0)
plt.plot(xs, sor_pts[d][p], "o", color=scol, markersize=4.0)
plt.show()
if __name__ == "__main__":
main()
, что приводит к
оси х этим количество элементов в L, ось у амортизируются время на зонд; зеленые точки sorted_probe(), синие - linear_probe().
Выводы:
- среды выполнения для обеих функций удивительно линейно относительно длины
- для одного зонда в L, предварительная сортировка примерно в 4 раза медленнее, чем итерация
- точка пересечения, как представляется, около 5 зондов; для этого меньше, линейный поиск быстрее, для большего, предварительная сортировка выполняется быстрее.
возможно дубликат [индекс списка Первого Python больше, чем x?] (http: // stackoverflow.com/questions/2236906/first-python-list-index-больше-than-x) –
не думайте так: хотите сначала больше, чем n-1, меньше n + 1 и как обращаться, если он не существует (быстро) – Joel
Неясно, чего вы ожидаете, если элемент не существует –