Check whether two lists are identical up to numerical error
Question:
I have two algorithms that theoretically should perform the same task, and I want to check if they really do.
They each returns a large list containing a mixture of datatypes (numbers, lists, strings). I want to check if the two lists are identical.
The simple method is assert list1 == list2
. However, due to numerical errors, sometimes an element in list1
is 5
and the corresponding element in list2
is 5.000003
. This still triggers the assertion False
, but I want to ignore such small error.
How to implement this "check for identity up to numerical errors"?
I think the fact that the lists contain a mixture of datatypes (not just numbers) complicates the problem.
Answers:
The basic formula would be something like:
len(list1) == len(list2) and all(is_close(a, b) for a, b in zip(list1, list2))
with some function is_close
that you use to compare two elements, maybe along the lines of:
def is_close(a, b):
return a == b or (
isinstance(a, (float, int)) and isinstance(b, (float, int))
and abs(a - b) < 0.000005
)
potentially with other exceptions to the general a == b
rule for different data types. It could even be defined recursively to handle nested data:
def is_close(a, b):
return a == b or (
isinstance(a, (float, int)) and isinstance(b, (float, int))
and abs(a - b) < 0.000005
) or (
isinstance(a, list) and isinstance(b, list)
and len(a) == len(b)
and all(is_close(*z) for z in zip(a, b))
) or (
isinstance(a, dict) and isinstance(b, dict)
and a.keys() == b.keys()
and all(is_close(a[k], b[k]) for k in a)
) # etc?
In short, you can create a custom list class and overload the ==
operator.
from collections import UserList
class CustomList(UserList):
def __eq__(self, other):
if CUSTOM LOGIC HERE:
return true
else:
return false
You could then use the CustomList as you would a built-in Python list.
my_custom_list = CustomList([1, 2, 3])
Since you only overload the __eq__
method, it will behave like a normal list except that it will have custom logic for comparing lists together.
I have two algorithms that theoretically should perform the same task, and I want to check if they really do.
They each returns a large list containing a mixture of datatypes (numbers, lists, strings). I want to check if the two lists are identical.
The simple method is assert list1 == list2
. However, due to numerical errors, sometimes an element in list1
is 5
and the corresponding element in list2
is 5.000003
. This still triggers the assertion False
, but I want to ignore such small error.
How to implement this "check for identity up to numerical errors"?
I think the fact that the lists contain a mixture of datatypes (not just numbers) complicates the problem.
The basic formula would be something like:
len(list1) == len(list2) and all(is_close(a, b) for a, b in zip(list1, list2))
with some function is_close
that you use to compare two elements, maybe along the lines of:
def is_close(a, b):
return a == b or (
isinstance(a, (float, int)) and isinstance(b, (float, int))
and abs(a - b) < 0.000005
)
potentially with other exceptions to the general a == b
rule for different data types. It could even be defined recursively to handle nested data:
def is_close(a, b):
return a == b or (
isinstance(a, (float, int)) and isinstance(b, (float, int))
and abs(a - b) < 0.000005
) or (
isinstance(a, list) and isinstance(b, list)
and len(a) == len(b)
and all(is_close(*z) for z in zip(a, b))
) or (
isinstance(a, dict) and isinstance(b, dict)
and a.keys() == b.keys()
and all(is_close(a[k], b[k]) for k in a)
) # etc?
In short, you can create a custom list class and overload the ==
operator.
from collections import UserList
class CustomList(UserList):
def __eq__(self, other):
if CUSTOM LOGIC HERE:
return true
else:
return false
You could then use the CustomList as you would a built-in Python list.
my_custom_list = CustomList([1, 2, 3])
Since you only overload the __eq__
method, it will behave like a normal list except that it will have custom logic for comparing lists together.