在Python中对落于可变范围内的数字进行舍入

0 投票
2 回答
2106 浏览
提问于 2025-04-18 08:39

我有一个数字列表:

lst = [3.253, -11.348, 6.576, 2.145, -11.559, 7.733, 5.825]

我想找个办法,把列表里的每个数字替换成一个给定的数字,前提是这个数字在某个范围内。我想根据输入列表的最小值和最大值,以及一个控制范围数量的输入数字,来创建多个范围。举个例子,如果我说我想要3个范围,均匀地分布在最小值和最大值之间。

numRanges = 3
lstMin = min(lst)
lstMax = max(lst)
step = (lstMax - lstMin) / numRanges

range1 = range(lstMin, lstMin + step)
range2 = range(range1 + step)
range3 = range(range2 + step)

那么,能不能让范围的数量由numRanges这个变量来决定呢?之后我想拿这个输入列表,比如说:

for i in lst:
    if i in range1:
        finalLst.append(1) #1 comes from range1 and will be growing if more ranges
    elif i in range2:
        finalLst.append(2) #2 comes from range2 and will be growing if more ranges
    else i in range3:
        finalLst.append(3) #3 comes from range2 and will be growing if more ranges

我现在觉得这一切都是“手动”的,我不太确定怎么让它变得更灵活,这样我只需要指定范围的数量和一个数字列表,代码就能自动处理剩下的事情。提前谢谢你的帮助。

finalLst = [3, 1, 3, 3, 1, 3, 3]

2 个回答

1

Python有一个非常好用的工具,专门用来处理这种工作,叫做bisect。假设你的范围列表是这样定义的:

ranges = [-15, -10, -5, 5, 10, 15]

对于你的输入列表,你只需要像这样调用bisect:

lst = [3.253, -11.348, 6.576, 2.145, -11.559, 7.733, 5.825]
results = [ranges[bisect(ranges, element)] for element in lst]

这样就会得到:

>>>[5, -10, 10, 5, -10, 10, 10]

你还可以通过在Python 2.7中使用ranges = range(start,stop,step),或者在Python 3.X中使用ranges = list(range(start,stop,step))来扩展到任何任意的范围列表。

更新

重新阅读你的问题,这可能更接近你想要的答案(仍然使用bisect):

from numpy import linspace
from bisect import bisect_left

def find_range(numbers, segments):
    mx = max(numbers)
    mn = mn(numbers)
    ranges = linspace(mn, mx, segments)
    return [bisect_left(ranges, element)+1 for element in numbers]

>>> find_range(lst, 3)
[3, 2, 3, 3, 1, 3, 3]
2

这段代码可以通过基本的数学运算在列表推导式中轻松实现:

numRanges = 3
lstMin = min(lst)
lstMax = max(lst) + 1e-12 # small value added to avoid floating point rounding issues
step = (lstMax - lstMin) / numRanges

range_numbers = [int((x-lstMin) / step) for x in lst]

这段代码会为原始列表中的每个值生成一个整数,其中0表示这个值属于第一个范围,1表示第二个范围,依此类推。它和你的代码几乎一样,只是数字是从0开始的,而不是1(如果你真的想从1开始,可以在计算中加个+ 1)。

我在lstMax中加的小值有两个原因。第一个是为了确保浮点数的舍入问题不会导致列表中的最大值返回numRange作为它的范围索引,而不是numRange-1(表示第numRange个范围)。另一个原因是为了避免在列表中只有一个值(可能重复多次)的情况下出现除以零的错误,这样min(lst)max(lst)会返回相同的结果。

撰写回答