给定一个整数列表,我想找到离输入的数字最接近的数字:
>>> myList = [4, 1, 88, 44, 3]
>>> myNumber = 5
>>> takeClosest(myList, myNumber)
...
4
有没有快速的方法可以做到这一点?给定一个整数列表,我想找到离输入的数字最接近的数字:
>>> myList = [4, 1, 88, 44, 3]
>>> myNumber = 5
>>> takeClosest(myList, myNumber)
...
4
有没有快速的方法可以做到这一点?如果我们不确定列表是否已排序,我们可以使用内置的min()
函数,找到与指定数字距离最小的元素。
>>> min(myList, key=lambda x:abs(x-myNumber))
4
{1: "a", 2: "b"}
。此方法需要 O(n) 时间。
min
实现,将其应用于字典 (items()
),并在最后返回键而不是值。 - Dustin Opreanumpy.argmin
д»Јжӣҝmin
жқҘиҺ·еҸ–зҙўеј•иҖҢдёҚжҳҜеҖјгҖӮ - user7345804我将把函数take_closest
重命名以符合PEP8命名规范。
如果你的意思是快速执行而不是快速编写的话,除了一个非常狭窄的用例之外,min
不应该是你的首选。 min
解决方案需要检查列表中的每个数字并为每个数字进行计算。使用bisect.bisect_left
几乎总是更快的。
“几乎”源于bisect_left
要求对列表进行排序才能工作。希望您的用例使您可以对列表进行一次排序,然后让其保持不变。即使不能这样做,只要您不需要在每次调用take_closest
之前进行排序,bisect
模块很可能会胜出。如果您有疑问,请尝试两种方法并查看现实世界的差异。
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
因此在这个特定的测试中,bisect
快了近20倍。对于更长的列表,差距会更大。
如果我们通过删除myList
必须排序的前提条件来公平竞争会怎样?让我们假设每次调用take_closest
时都对列表的副本进行排序,同时保持min
解决方案不变。对于上面测试中的200个项目列表,bisect
解决方案仍然是最快的,但只快了约30%。
这是一个奇怪的结果,考虑到排序步骤为O(n log(n))!min
仍然失败的唯一原因是,排序是在高度优化的C代码中完成的,而min
必须沿着调用每个项目的lambda函数缓慢前进。随着myList
的增长,min
解决方案最终将更快。请注意,我们必须让所有东西都支持min
解决方案才能获胜。
a=range(-1000,1000,2);random.shuffle(a)
,您会发现takeClosest(sorted(a), b)
会变得更慢。 - kennytmgetClosest
可能会被每次排序调用多次,这将更快,并且对于仅排序一次的情况,这是一个不言而喻的选择。 - Lauritz V. ThaulowmyList
已经是np.array
,那么使用np.searchsorted
替换bisect
会更快。 - Michael Hall>>> takeClosest = lambda num,collection:min(collection,key=lambda x:abs(x-num))
>>> takeClosest(5,[4,1,88,44,3])
4
Lambda表达式是一种特殊的写法,用于编写“匿名”函数(即无名称的函数)。因为lambda是一个表达式,所以你可以给它任何想要的名称。
上述代码的“长写法”为:
def takeClosest(num,collection):
return min(collection,key=lambda x:abs(x-num))
def closest(list, Number):
aux = []
for valor in list:
aux.append(abs(Number-valor))
return aux.index(min(aux))
这段代码将为你提供列表中最接近目标数字的索引。
KennyTM提供的解决方案是最好的,但在某些情况下无法使用(例如brython),这个函数可以胜任。
遍历列表并将当前最接近的数字与 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
if abs(myList[i] - myNumber) < abs(closest - myNumber): closest = myList[i];
。不过最好事先将该值存储起来。 - lk_vcdef 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])
np
是什么意思? - munmunbb>>> myList = [1, 3, 4, 44, 88]
>>> myNumber = 5
>>> pos = (bisect_left(myList, myNumber))
>>> myList[pos]
...
44
>>> import numpy as np
>>> myNumber = 5
>>> myList = [1, 3, 4, 44, 88]
>>> myArray = np.array(myList)
>>> pos = (np.abs(myArray-myNumber)).argmin()
>>> myArray[pos]
...
4
np.searchsorted
代替bisect_left
。而@Kanat是正确的 - Lauritz的解决方案确实包括选择哪个候选者更接近的代码。 - John Y如果我可以补充@Lauritz's answer
为了避免运行错误,在bisect_left
行之前不要忘记添加条件:
if (myNumber > myList[-1] or myNumber < myList[0]):
return False
因此完整的代码将如下所示:
from bisect import bisect_left
def takeClosest(myList, myNumber):
"""
Assumes myList is sorted. Returns closest value to myNumber.
If two numbers are equally close, return the smallest number.
If number is outside of min or max return False
"""
if (myNumber > myList[-1] or myNumber < myList[0]):
return False
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
FOR
循环进程中,列表中的值可以替换为微分值。def f_ClosestVal(v_List, v_Number):
"""Takes an unsorted LIST of INTs and RETURNS INDEX of value closest to an INT"""
for _index, i in enumerate(v_List):
v_List[_index] = abs(v_Number - i)
return v_List.index(min(v_List))
myList = [1, 88, 44, 4, 4, -2, 3]
v_Num = 5
print(f_ClosestVal(myList, v_Num)) ## Gives "3," the index of the first "4" in the list.
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)