我有一个元组列表,其中一个元素为NaN
:
l = [('a', 7.0), ('b', float('nan'))]
我想在上面的列表中找到元组('b', float('nan'))
的索引
l.index(('b', float('nan'))
无法在列表中找到元素,即使它的索引是1。将ValueError
异常抛出为:
>>> l.index(('b', float('nan'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: ('b', nan) is not in list
这很可能是由于每个float('nan')
都是一个独立的NaN对象,这意味着这两个元组也是不同的对象。
我一般如何解决这个问题?
float('nan') == float('nan')
返回False
,因为它被设计为不与自身匹配。这就是为什么list.index()
函数无法找到NaN
值的匹配并引发ValueError
异常的原因。
请阅读为什么NaN不等于NaN?了解更多有关此行为的信息。
下面是一个自定义函数check_nan_match()
,用于检查传递的对象是否具有相同的值。这个函数将能够匹配NaN
对象也基于上述属性,即NaN
s返回False
与自身匹配。
# Function too check passed values are match, including `NaN`
def check_nan_match(a, b):
return (b != b and a != a) or a == b
# ^ ^ `NaN` property to return False when matched with itself
为了在包含NaN
的list
中获得tuple
的索引,这里我创建了另一个自定义函数get_nan_index
。该函数接受my_list
和my_tuple
作为参数,在my_list
上迭代以获得my_tuple
的索引。为了检查是否相等,我使用以前创建的check_nan_match
函数,该函数也能够匹配NaN
值。
# Get index from list of tuple , when tuple is passed
def get_nan_index(my_list, my_tuple):
for i, t in enumerate(my_list):
if all(check_nan_match(x, y) for x, y in zip(t, my_tuple)):
return i
else:
raise ValueError # Raise `ValueError` exception in case of no match.
# Similar to `list.index(...)` function
示例运行:
# check for tuple with `NaN`
>>> get_nan_index([('a', 7.0), ('b', float('nan'))], ('b', float('nan')))
1
# check for tuple without `NaN`
>>> get_nan_index([('a', 1), ('b', 2)], ('b', 2))
1
# `ValueError` exception if no match
>>> get_nan_index([('a', 7.0), ('b', 3)], ('b', float('nan')))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in get_nan_index
ValueError