比较列表中整数与给定值的差异

3

我的Python有点生疏,对于这个极其简单的算法我真的很困扰。

我正在尝试编写一个函数,该函数接受两个参数(目标值和数值列表),以查找数值列表中最靠近目标值的数字;如果存在并列,则选择更小的数字。

这是我的进展,但我仅选择了较低的数字,而没有实际比较列表中的值与目标的相对距离之间的差异。

因此,实际上,我的函数根本没有正确完成挑战,因为47实际上比31更接近46;但是,如果列表中包含的数字是45和47(假设),那么它们将与我的目标数字等距,因此应打印45而不是47。

我希望答案使用简单的for/if/while循环,以便我可以真正练习我的技能。

其他更高级的答案也欢迎详细解释。

编辑

你们的一些非常好的答案,非常感谢;我正在测试它们,并将选择最适合我的风格的答案,并将其余的用作参考,即使你有最好的一行答案。

target = 46
values = [1, 22, 31, 47, 87, 99]

def closest_to_target(target, values):

    lower = []

    for number in values:
        if number < target:
            lower.append(number)

    if lower:
        lowest = sorted(lower, reverse=True)[0]
        return lowest

    else:
        return "Error handling array"


print closest_to_target(target, values)

你是想要最接近的数字(在这个例子中是 47),还是想要刚好小于目标数的数字(这里是 31)?此外,你是否喜欢使用循环?我认为列表推导式更适合这种情况。 - RishiG
我实际上只是在回答你的问题时添加了更多信息,从“因此,在本质上…”开始;是的,在这种情况下,47应该返回而不是31。 - pythlang
请查看 https://dev59.com/VWct5IYBdhLWcg3wXsXH...,那里有很多关于在列表中找到最接近给定值的数的解决方案。 - RishiG
很好的发现,我确实查看了那篇帖子,但出于某种原因我无法使其正常工作,而且它还假定了一个已排序的数组。不幸的是,我很难在不使用lambda的情况下理解这样一个简单的问题。 - pythlang
5个回答

4

您只选择小于目标值的数字,而不考虑差异。针对您的要求,这是一个基本的代码示例,您需要考虑在线性搜索上进行修改,但仅跟踪最低差异和产生此最低差异的值。

    def closest(target, values):
        smallest_difference = #a really large value to start
        closest_number = None
        for number in values:
            diff = abs(number - target)
            if diff == smallest_difference and number < closest_number:
               closest_number = number
            if diff < smallest_difference:
               closest_number = number
               smallest_difference = diff
        return closest_number

这种方法的优点在于您不需要创建额外的列表。

我可以这样做 smallest_difference= [ ],因为在等号后面什么也不加会抛出错误。我喜欢这个答案,因为它真正展示了编程技巧,而不仅仅是像lambda这样的函数,虽然它们显然很好,但在练习时并不是最好的选择。 - pythlang
感谢您的回答,@meeja;您的答案完美地符合了我的标准,并且与我编写原始代码的风格相符,因此我已经接受了您的答案,尽管还有其他同样出色和信息丰富的答案。 - pythlang

3
您可以使用以下函数,它会创建值的元组,并显示该值接近目标值的程度。通过按照这个元组进行排序,您不仅可以得到最接近目标值的元素,而且在有多个相同接近程度的值时,会选择其中最小的值。
target = 46
values = [1, 22, 31, 47, 87, 99]

def closest_min(l, t):
  return sorted([(abs(t-i), l[e]) for e, i in enumerate(l)])[0][1]

print(closest_min(values, target))

输出:

47

在平局的情况下,会正确选择最低的一个。
>>> closest_min([47, 45], 46)
45

使用min()稍微整洁一点的版本:
def closest_min(l, t):
      return min(l, key=lambda x:(abs(x-t), x))

3

这可以通过单次操作完成,并跟踪差异。如果差值等于之前的差值,则最接近值为之前最接近值和当前值中的较小值。如果差值较小,则使用当前值更新差值和最接近值。否则,继续进行。

>>> target = 46
>>> values = [1, 22, 31, 47, 87, 99]
>>> closest = values[0]
>>> delta = abs(target - closest)
>>> for x in values:
...     d = abs(target - x)
...     if d == delta:
...         closest = min(closest, x)
...     elif d < delta:
...         delta = d
...         closest = x
...
>>> delta
1
>>> closest
47
>>>

1
def min_dist_index(target, values):
    values = sorted(values)
    dists = [abs(target-value) for value in values]
    index = dists.index(min(dists))
    return values[index]

target = 46
values = [1, 22, 31, 47, 87, 99]
print(min_dist_index(target, values))

输出:47



-1
您可以生成一个有效数字列表,然后可以使用所谓的列表推导式进行处理:
values[[abs(target-i) for i in values].index(min([abs(target-i) for i in values]))]

在这里,列表字面量[]用于定义通用算法,而不是特定值的内容。列表中的每个元素i都来自包含您的值的列表文字,并针对目标数字进行检查。如果它们不符合条件,则不包含在新生成的列表中。

实现:

#!/usr/bin/env python

target = 46
values = [1, 22, 31, 47, 87, 99]


def closest_to_target(target, values):
    lower = values[[abs(46-i) for i in values].index(min([abs(46-i) for i in values]))]
    return lower

print(closest_to_target(target, values))

这将会打印:

47


你能展示一个函数内的实现吗?如果它能正常工作,我会接受你的答案。 - pythlang
实际上,这个做的几乎和我的一样,只是更加优雅哈哈。不幸的是,它实际上没有比较值之间的差异。另外,在索引中获取最后一个项目,我只需要在lower=的末尾添加[-1]即可。 - pythlang
1
是的,我也注意到了。更多的是关于从绝对值创建数组的方式,然后使用具有最低值的索引来获取值的方法。 - What
1
@pythlang 我更新了我的帖子。这个版本返回47。 - What
1
很抱歉要说,但你的代码看起来很奇怪。特别是这一部分:lower = values[[abs(target-i) for i in values].index(min(values))] - 如果你将目标更改为2,列表更改为[100, 22, 31, 47, 87, 99],它会崩溃并显示 ValueError: 22 is not in list。你得到的结果是47,并不意味着它是完全正确的。 - Patrick Artner
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接