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.

Asked By: Felix Fourcolor

||

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?
Answered By: Samwise

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.

Answered By: Evan Ottinger
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.