提问人:Justin 提问时间:11/11/2023 更新时间:11/11/2023 访问量:56
在 Python 中比较浮点数时遇到问题
Trouble comparing floats in Python
问:
我知道这应该更容易,但我在比较浮点值时遇到了问题。
我有一些非常基本的代码,可以做一些事情:
- 任何低于 5 的权重都将添加到light_pkgs。
- 任何超过 15 的权重都将添加到heavy_pkgs。
- 任何超过 15 的权重都将从原始列表中删除。
packages
def process_packages(package_list):
light_pkgs = []
heavy_pkgs = []
light_weight = 5.00
heavy_weight = 15.00
for i in package_list:
if i < light_weight:
light_pkgs.append(i)
elif i > heavy_weight:
heavy_pkgs.append(i)
packages.remove(i)
return light_pkgs, heavy_pkgs
packages = [2.4, 3.44, 4.55, 4.9, 5.11, 5.31, 5.61, 5.99, 6.11, 7.34, 7.9, 9, 11.3, 15.1, 15.31, 15.68, 15.9, 16.7, 19.3, 21]
print(process_packages(packages))
print(packages)
我相信由于精度错误,我的代码无法识别 15.xx 范围内的几个数字。
此外,我仅限于使用内置的 Python 函数。
预期输出:
([2.4, 3.44, 4.55, 4.9], [15.1, 15.31, 15.68, 15.9, 16.7, 19.3, 21])
[2.4, 3.44, 4.55, 4.9, 5.11, 5.31, 5.61, 5.99, 6.11, 7.34, 7.9, 9, 11.3]
实际输出:
([2.4, 3.44, 4.55, 4.9], [15.1, 15.68, 16.7, 21])
[2.4, 3.44, 4.55, 4.9, 5.11, 5.31, 5.61, 5.99, 6.11, 7.34, 7.9, 9, 11.3, 15.31, 15.9, 19.3]
如您所见,几个大于 15 的数字不会被添加到heavy_pkgs列表中,也不会从原始包列表中删除。
答:
您遇到了如何在迭代时从列表中删除项目?中的问题。
packages
在全局作用域中与在函数的作用域中是相同的(它们都是相同 的别名)。当您在迭代它时从它开始迭代时,您将跳过紧跟在已删除元素之后的元素(因为它向下移动了一个槽,并且迭代器在下一个循环中前进过该槽)。package_list
list
remove
用轻量级和中等权重构建一个新的,并在循环完成后替换内容,事情应该可以工作(并且工作效率更高,因为每次调用 是 ,所以整体工作是 ,而两次通过构建和替换是)。list
package_list
remove
O(n)
O(n²)
O(n)
def process_packages(package_list):
light_pkgs = []
not_heavy_pkgs = [] # Temporary list to hold stuff that should remain in package_list
heavy_pkgs = []
light_weight = 5.00
heavy_weight = 15.00
for i in package_list:
if i < light_weight:
light_pkgs.append(i)
not_heavy_pkgs.append(i) # Looks like light things are supposed to stay in too
elif i > heavy_weight:
heavy_pkgs.append(i)
else:
not_heavy_pkgs.append(i) # It's not heavy, so retain it
package_list[:] = not_heavy_pkgs # Assigning to complete slice replaces contents of
# package_list in place, affecting caller's version of list
# as your original code tried to do
return light_pkgs, heavy_pkgs
该代码确实有点笨拙。虽然这将涉及对输入的更多传递,但在这里依赖一些列表推导会更简洁:
def process_packages(package_list):
heavy_weight = 15.0
# Get heavy packages
heavy_pkgs = [pkg for pkg in package_list if pkg > heavy_weight]
# Remove heavy packages from source
package_list[:] = [pkg for pkg in package_list if pkg <= heavy_weight]
# One more pass to get light packages and we're done
# This pass is somewhat cheaper, because heavy items were already removed
return [pkg for pkg in package_list if pkg < 5.0], heavy_pkgs
评论
当您从 for 循环中删除一个项目时,哪个项目将成为下一个索引? 例如,如果您删除第 3 项(即 idx 3),则删除后第 4 项将成为第 3 项。(就像有人从队列中走出来一样,他旁边的人会来到他的位置)。即使在删除之后,循环也会按升序进行。所以在索引 3 之后,下一个索引是 4。但是由于之前的 index-4 现在已经变成了 index-3,现在的 index-4 就是之前的 index-5。因此,即使之前的索引 4 超过 15,也不会删除。
因此,不要使用 for 循环,而应使用 while 循环。如果删除了该项目,则将索引值减少 1,并将package_list的长度减少 1。就是这样。
def process_packages(package_list):
light_pkgs = []
heavy_pkgs = []
L = len(package_list)
i = 0
light_weight = 5.00
heavy_weight = 15.00
while i<L:
x = package_list[i]
if x < light_weight:
light_pkgs.append(x)
elif x > heavy_weight:
heavy_pkgs.append(x)
packages.remove(x)
i = i-1
L = L-1
i += 1
return light_pkgs, heavy_pkgs
#Output:
([2.4, 3.44, 4.55, 4.9], [15.1, 15.31, 15.68, 15.9, 16.7, 19.3, 21])
[2.4, 3.44, 4.55, 4.9, 5.11, 5.31, 5.61, 5.99, 6.11, 7.34, 7.9, 9, 11.3]
评论
下一个:为什么这个方位计算如此不准确?
评论
packages
def process_packages(package_list):
packages.remove(i)
package_list
packages.remove(i)
def process_packages(package_list):
packages