给定一个整数列表,我想找到哪个数字最接近我输入的数字:

>>> myList = [4, 1, 88, 44, 3]
>>> myNumber = 5
>>> takeClosest(myList, myNumber)
...
4

有什么快速的方法吗?


当前回答

如果我们不确定列表是否已排序,可以使用内置的min()函数来查找与指定数字距离最小的元素。

>>> min(myList, key=lambda x:abs(x-myNumber))
4

注意,它也适用于具有int键的字典,如{1:"a", 2: "b"}。该方法耗时O(n)。


如果列表已经排序了,或者你可以只对数组排序一次,使用@Lauritz的回答中说明的平分方法,它只需要O(log n)时间(注意,检查列表是否已经排序是O(n),排序是O(n log n))。

其他回答

我将重命名函数take_nearest以符合PEP8命名约定。

如果你指的是快速执行而不是快速编写,那么min不应该是你选择的武器,除非在一个非常狭窄的用例中。最小解需要检查列表中的每个数字,并对每个数字进行计算。使用平分。而Bisect_left几乎总是更快。

“几乎”来自于bisect_left需要对列表进行排序才能工作的事实。希望您的用例是这样的,您可以对列表进行一次排序,然后不去管它。即使不是这样,只要您不需要在每次调用take_nearest之前进行排序,那么平分模块很可能会排在最前面。如果你有疑问,两种都试一下,看看现实世界的区别。

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的工作原理是将列表重复分成两半,并通过查看中间值来找出myNumber必须位于哪一半。这意味着它的运行时间为O(log n),而投票最多的答案的运行时间为O(n)。如果我们比较这两个方法,并为它们提供一个排序后的myList,结果如下:

$ 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

在这个测试中,平分法几乎快20倍。对于较长的列表,差异会更大。

如果我们通过移除myList必须排序的前提条件来创造一个公平的竞争环境呢?假设每次调用take_nearest时,我们对列表的一个副本进行排序,同时保持最小解不变。使用上述测试中的200项列表,平分解决方案仍然是最快的,尽管只快了大约30%。

这是一个奇怪的结果,考虑到排序步骤是O(nlog (n))!min仍然失败的唯一原因是排序是在高度优化的c代码中完成的,而min必须为每一项调用lambda函数。随着myList规模的增长,最小解最终会更快。请注意,为了让最小解获胜,我们必须把一切都叠在对它有利的地方。

遍历列表并将当前最接近的数字与abs(currentNumber - myNumber)进行比较:

def takeClosest(myList, myNumber):
    closest = myList[0]
    for i in range(1, len(myList)):
        if abs(i - myNumber) < closest:
            closest = i
    return closest
def takeClosest(myList, myNumber):
    newlst = []
    for i in myList:
        newlst.append(i - myNumber)
    lstt = [abs(ele) for ele in newlst]
    print(myList[lstt.index(min(lstt))])

myList = [4, 1, 88, 44, 3]
myNumber = 5
takeClosest(myList,myNumber)
def find_nearest(array, value):
    array = np.asarray(array)
    idx = (np.abs(array - value)).argmin()
    return array[idx]

通过使用

price_near_to=find_nearest(df['Close'], df['Close'][-2])
def closest(list, Number):
    aux = []
    for valor in list:
        aux.append(abs(Number-valor))

    return aux.index(min(aux))

这段代码将为您提供列表中与number最接近的数字的索引。

KennyTM给出的解决方案是最好的,但在您不能使用它的情况下(如brython),这个函数将完成工作