如何在Python中比较列表?

3
我有一个列表。
a = [1.0, 2.0, 2.1, 3.0, 3.1, 4.2, 5.1, 7.2, 9.2]

我希望将此列表与其他列表进行比较,同时提取有关列表内容的数字顺序信息。所有其他列表都具有与a相同的元素。

因此我尝试了以下内容:

a = [1.0, 2.0, 2.1, 3.0, 3.1, 4.2, 5.1, 7.2, 9.2]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print dict(zip(a,b))

a1=[2.1, 3.1, 4.2, 7.2]

我想将a1与a进行比较,并提取字典值[3, 5, 6, 8]
1个回答

6
只需循环遍历 a1,并查看在您创建的字典中是否存在匹配的键即可:
mapping = dict(zip(a, b))
matches = [mapping[value] for value in a1 if value in mapping]

示例:

>>> a = [1.0, 2.0, 2.1, 3.0, 3.1, 4.2, 5.1, 7.2, 9.2]
>>> b = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a1 = [2.1, 3.1, 4.2, 7.2]
>>> mapping = dict(zip(a, b))
>>> [mapping[value] for value in a1 if value in mapping]
[3, 5, 6, 8]

然而,请注意你正在使用 浮点数。由于浮点数是十进制值的二进制近似值,因此可能无法完全匹配值;例如,值2.999999999999999(15个9)可能被Python的str()函数呈现为3.0,但并不等于3.0

>>> 2.999999999999999
2.999999999999999
>>> str(2.999999999999999)
'3.0'
>>> 2.999999999999999 == 3.0
False
>>> 2.999999999999999 in mapping
False

如果您的输入列表 a 已排序,您可以使用 math.isclose() 函数(或其后移版本),结合 bisect 模块 来保持匹配的高效性:
import bisect
try:
    from math import isclose
except ImportError:
    def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
        # simplified backport, doesn't handle NaN or infinity.
        if a == b: return True
        return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

result = []
for value in a1:
    index = bisect.bisect(a, value)
    if index and isclose(a[index - 1], value):
        result.append(b[index - 1])
    elif index < len(a) and isclose(a[index], value):
        result.append(b[index])

这个测试每个输入值最多从a中提取两个值;一个保证等于或低于(在index - 1),另一个更高的值。对于你的样本a,值2.999999999999999被二分到索引3,位于2.13.0之间。由于isclose(3.0, 2.999999999999999)为真,这仍然可以让您将该值映射到b中的4


彼得,谢谢。列表中的数字是FORTRAN代码的执行结果,格式为f11.5。因此,我认为简单版本就足够了! - Richard Rublev
没错,如果你有字符串,那么你可以很好地绕过这个问题。 - Martijn Pieters

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