I’ll rename the function take_closest
to conform with PEP8 naming conventions.
If you mean quick-to-execute as opposed to quick-to-write, min
should not be your weapon of choice, except in one very narrow use case. The min
solution needs to examine every number in the list and do a calculation for each number. Using bisect.bisect_left
instead is almost always faster.
The «almost» comes from the fact that bisect_left
requires the list to be sorted to work. Hopefully, your use case is such that you can sort the list once and then leave it alone. Even if not, as long as you don’t need to sort before every time you call take_closest
, the bisect
module will likely come out on top. If you’re in doubt, try both and look at the real-world difference.
from bisect import bisect_left
def take_closest(myList, myNumber):
"""
Assumes myList is sorted. Returns closest value to myNumber.
If two numbers are equally close, return the smallest number.
"""
pos = bisect_left(myList, myNumber)
if pos == 0:
return myList[0]
if pos == len(myList):
return myList[-1]
before = myList[pos - 1]
after = myList[pos]
if after - myNumber < myNumber - before:
return after
else:
return before
Bisect works by repeatedly halving a list and finding out which half myNumber
has to be in by looking at the middle value. This means it has a running time of O(log n) as opposed to the O(n) running time of the highest voted answer. If we compare the two methods and supply both with a sorted myList
, these are the results:
$ python -m timeit -s " from closest import take_closest from random import randint a = range(-1000, 1000, 10)" "take_closest(a, randint(-1100, 1100))" 100000 loops, best of 3: 2.22 usec per loop $ python -m timeit -s " from closest import with_min from random import randint a = range(-1000, 1000, 10)" "with_min(a, randint(-1100, 1100))" 10000 loops, best of 3: 43.9 usec per loop
So in this particular test, bisect
is almost 20 times faster. For longer lists, the difference will be greater.
What if we level the playing field by removing the precondition that myList
must be sorted? Let’s say we sort a copy of the list every time take_closest
is called, while leaving the min
solution unaltered. Using the 200-item list in the above test, the bisect
solution is still the fastest, though only by about 30%.
This is a strange result, considering that the sorting step is O(n log(n))! The only reason min
is still losing is that the sorting is done in highly optimalized c code, while min
has to plod along calling a lambda function for every item. As myList
grows in size, the min
solution will eventually be faster. Note that we had to stack everything in its favour for the min
solution to win.
Для неотсортированного массива. Для отсортированного лучше использовать бинпоиск.
Python 3.4+: tio.run
def f(a, val):
return min((x for x in a if x > val), default=None)
a = [1, 2, 5, 22, 33, 44, 312]
print(f(a, 3))
print(f(a, 10))
print(f(a, 1000))
Более ранние версии: tio.run
def f(a, val):
return min([x for x in a if x > val] or [None])
a = [1, 2, 5, 22, 33, 44, 312]
print(f(a, 3))
print(f(a, 10))
print(f(a, 1000))
Вывод в обоих случаях:
5
22
None
Задача: Найдите ближайшее значение к переданному.
Вам даны список значений в виде множества (Set) и значение, относительно которого, надо найти ближайшее.
Несколько уточнений:
Если 2 числа находятся на одинаковом расстоянии — необходимо выбрать наименьшее из них;
Ряд чисел всегда не пустой, т.е. размер >= 1;
Переданное значение может быть в этом ряде, а значит оно и является ответом;
В ряде могут быть как положительные, так и отрицательные числа, но они всегда целые;
Ряд не отсортирован и состоит из уникальных чисел.
Решение предлагают такое:
def nearest_value(values: set, one: int) -> int:
return min(values, key=lambda n: (abs(one - n), n))
Как работает часть (abs(one — n), n)?
Напишите программу, которая находит в массиве элемент, самый близкий по величине к данному числу.
Входные данные
В первой строке содержатся список чисел — элементы массива (целые числа, не превосходящие 1000
по абсолютному значению).
Во второй строке вводится одно целое число x
, не превосходящее 1000
по абсолютному значению.
Выходные данные
Вывести значение элемента массива, ближайшего к x
. Если таких чисел несколько, выведите любое из них.
Python | ||
|
Permalink
Cannot retrieve contributors at this time
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Напишите программу, которая находит в массиве элемент, самый близкий по величине к данному числу. | |
l = input() | |
numbers = list(map(int, input().strip().split())) | |
x = int(input().strip()) | |
res = numbers[0] | |
for i in numbers: | |
if abs(i — x) < abs(res — x): | |
res = i | |
print(res) |