如何检查一个列表是否是另一个列表的子集(带有误差容忍度)

3
我将尝试解决一个问题,涉及确定一个列表是否是另一个列表的子集,但有一个额外的转折:只要值在公差范围内,代码应该认为该列表是一个子集,即使它们并不完全匹配。
例子: 如果我有以下列表:
A = [0.202, 0.101]
B = [0.1, 0.2, 0.3, 0.4, 0.5]

如果我设置公差为tol = 0.002,那么代码应该返回列表A是列表B的子集,因为它的值在公差范围内(0.202 <= 0.2 + tol0.101 <= 0.1 + tol)。

我没有太多的代码来展示,因为我知道如何使用传统的issubset函数确定一个列表是否是另一个列表的子集,但我不确定如何将公差合并到其中。

1个回答

9
你可以按照以下步骤进行操作(先提供伪代码):
For each elment a of A:
    for each element b of B:
        if a is close enough to b, consider a to be in B
    if a was not close enough to an element in B, break the loop as A is not a subset of B

但请注意,处理浮点数是危险的。根据此帖子,我们可以使用decimal模块进行比较。
将其简化为Python代码如下:
from decimal import Decimal

for a in A:
    for b in B:
        if abs(Decimal(str(a)) - Decimal(str(b))) <= tol:
            break
    else:
        print('A is not a subset of B')
        break
else:
    print(f"A is a subset of B with a tolerance of {tol}")

现在使用生成器和函数更加紧凑:

def tol_subset(A, B, tol):
    return all(any(abs(Decimal(str(a)) - Decimal(str(b))) <= tol for b in B) for a in A)

2
我总是忘记 for-else……谢谢!continue 应该打破外部 for 循环,但当然这不起作用。说实话,我总是只用生成器版本,所以可能没有为另一个版本付出足够的努力…… - CallMeStag
@ThatNewGuy 这种情况只会在列表不是子集的情况下发生,所以没问题...请阅读我上面提供的链接。如果条件满足并且第一个 break 被执行,那么 else 部分根本不会被执行。 - Tomerikoo
这个代码不是总会运行 print(f"A is a subset of B with a tolerance of {tol}") 的吗? - Hugo
@Tomerikoo 我误读了问题,我以为我们是在检查A中是否有任何一个元素在B中容差范围内。 - ThatNewGuy
1
@Hugo 不会。如果执行了第一个 else,那么它会打破外部循环,因此其 else 子句将不会被执行。 - Tomerikoo
显示剩余3条评论

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