Reputation: 838
I have a list of tuples with one element as NaN
:
l = [('a', 7.0), ('b', float('nan'))]
And I want to find the index of tuple ('b', float('nan'))
in the above list.
l.index(('b', float('nan'))
is unable to find the element in the list even though its index is 1. It is raising ValueError
exception as:
>>> l.index(('b', float('nan'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: ('b', nan) is not in list
Most likely this is due to the fact that each float('nan')
is an independent NaN object, meaning that the two tuples are different objects as well.
How do I solve this problem in general?
Upvotes: 2
Views: 552
Reputation: 48090
float('nan') == float('nan')
returns False
because it is designed to not to match with itself. That's why list.index()
function is unable to find a match for NaN
value and is raising ValueError
exception.
Please read Why is NaN not equal to NaN? to know more about this behaviour.
Below is a custom function check_nan_match()
to check whether passed objects are having same value or not. This function will be able to match for NaN
objects too based on the above property i.e. NaN
s return False
when matched with itself.
# 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
To get the index of tuple
in the list
containing NaN
, here I am creating another custom function as get_nan_index
. This function accepts my_list
and my_tuple
as param, iterates over the my_list
to get the index of my_tuple
. To check for the equality, I am using previously created check_nan_match
function which is capable to match NaN
values too.
# 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
Sample run:
# 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
Upvotes: 2