从整数列表中获取最接近给定值的数字

2024-12-30 08:41:00
admin
原创
40
摘要:问题描述:给定一个整数列表,我想找出最接近我输入的数字的数字:>>> myList = [4, 1, 88, 44, 3] >>> myNumber = 5 >>> takeClosest(myList, myNumber) ... 4 有什么快速的方法可...

问题描述:

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

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

有什么快速的方法可以做到这一点吗?


解决方案 1:

如果我们不确定列表是否已排序,我们可以使用内置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)。)

解决方案 2:

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

如果您指的是快速执行而不是快速写入,那么这不min应该是您的首选武器,除非在一种非常狭窄的用例中。解决方案需要检查列表中的每个数字为每个数字进行计算。使用替代方法几乎总是更快。min`bisect.bisect_left`

“几乎” 是因为bisect_left需要对列表进行排序才能工作。希望您的用例是这样的,您可以对列表进行一次排序,然后不管它。即使不是,只要您不需要在每次调用 之前进行排序take_closestbisect模块就很可能会名列前茅。如果您有疑问,请尝试两者并查看现实世界的差异。

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 "
从最近导入 take_closest
从随机导入 randint
a = 范围 (-1000, 1000, 10)” “take_closest (a, randint (-1100, 1100))”

100000 次循环,3 次中最佳:每次循环 2.22 微秒

$ python -m timeit -s "
从最近导入的 with_min
从随机导入 randint
a = 范围(-1000,1000,10)“”with_min(a,randint(-1100,1100))“

10000 次循环,3 次中最佳:每次循环 43.9 微秒

因此,在这个特定的测试中,bisect速度几乎快了 20 倍。对于较长的列表,差异会更大。

如果我们通过删除必须排序的前提条件来让竞争环境变得公平,myList结果会怎样?假设我们每次 take_closest调用时都对列表的副本进行排序,同时保持min解决方案不变。在上述测试中使用 200 个项目的列表,该bisect解决方案仍然是最快的,尽管只快了约 30%。

考虑到排序步骤是O(n log(n)),这是一个奇怪的结果!仍然失败的唯一原因min是排序是在高度优化的 c 代码中完成的,而 whilemin必须为每个项目调用 lambda 函数。随着myList规模的扩大,min解决方案最终会更快。请注意,我们必须将所有有利于min解决方案的东西都堆叠起来才能获胜。

解决方案 3:

>>> 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))

解决方案 4:

def closest(list, Number):
    aux = []
    for valor in list:
        aux.append(abs(Number-valor))

    return aux.index(min(aux))

此代码将为您提供列表中最接近数字的索引。

KennyTM 给出的解决方案总体上是最好的,但在你无法使用它的情况下(如 brython),此功能将完成工作

解决方案 5:

遍历列表并将当前最接近的数字与进行比较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

解决方案 6:

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])

解决方案 7:

值得注意的是,Lauritz 建议使用 bisect 实际上并没有在 MyList 中找到与 MyNumber 最接近的值。相反,bisect 会在 MyList 中按顺序查找MyNumber 之后的下一个值。因此,在 OP 的案例中,您实际上会得到 44 的位置,而不是 4 的位置。

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

为了获取最接近 5 的值,您可以尝试将列表转换为数组,然后像这样使用 numpy 中的 argmin。

>>> 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

我不知道这会有多快,我的猜测是“不是很快”。

解决方案 8:

扩展 Gustavo Lima 的答案。无需创建全新列表即可完成相同的操作。随着循环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.

解决方案 9:

如果我可以补充@Lauritz 的答案

为了避免运行错误,不要忘记在行前添加条件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

解决方案 10:

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)
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   997  
  在项目管理领域,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节,它不仅验证了项目团队的专业能力,还直接关系到项目的成功与否。在这一评审过程中,沟通技巧的运用至关重要。有效的沟通不仅能够确保信息的准确传递,还能增强团队协作,提升评审效率。本文将深入探讨CDCP...
华为IPD流程   34  
  IPD(Integrated Product Development,集成产品开发)是一种以客户需求为核心、跨部门协同的产品开发模式,旨在通过高效的资源整合和流程优化,提升产品开发的成功率和市场竞争力。在IPD培训课程中,掌握关键成功因素是确保团队能够有效实施这一模式的核心。以下将从五个关键成功因素展开讨论,帮助企业和...
IPD项目流程图   40  
  华为IPD(Integrated Product Development,集成产品开发)流程是华为公司在其全球化进程中逐步构建和完善的一套高效产品开发管理体系。这一流程不仅帮助华为在技术创新和产品交付上实现了质的飞跃,还为其在全球市场中赢得了显著的竞争优势。IPD的核心在于通过跨部门协作、阶段性评审和市场需求驱动,确保...
华为IPD   39  
  华为作为全球领先的通信技术解决方案提供商,其成功的背后离不开一套成熟的管理体系——集成产品开发(IPD)。IPD不仅是一种产品开发流程,更是一种系统化的管理思想,它通过跨职能团队的协作、阶段评审机制和市场需求驱动的开发模式,帮助华为在全球市场中脱颖而出。从最初的国内市场到如今的全球化布局,华为的IPD体系在多个领域展现...
IPD管理流程   71  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用