DeepDiff 5.5.0 documentation!

Other Parameters

Iterable Compare Func

New in DeepDiff 5.5.0

There are times that we want to guide DeepDiff as to what items to compare with other items. In such cases we can pass a iterable_compare_func that takes a function pointer to compare two items. The function takes three parameters (x, y, level) and should return True if it is a match, False if it is not a match or raise CannotCompare if it is unable to compare the two.

For example take the following objects:

Now let’s define a compare_func that takes 3 parameters: x, y and level.

>>> from deepdiff import DeepDiff
>>> from deepdiff.helper import CannotCompare
>>>
>>> t1 = [
...     {
...         'id': 1,
...         'value': [1]
...     },
...     {
...         'id': 2,
...         'value': [7, 8, 1]
...     },
...     {
...         'id': 3,
...         'value': [7, 8],
...     },
... ]
>>>
>>> t2 = [
...     {
...         'id': 2,
...         'value': [7, 8]
...     },
...     {
...         'id': 3,
...         'value': [7, 8, 1],
...     },
...     {
...         'id': 1,
...         'value': [1]
...     },
... ]
>>>
>>> DeepDiff(t1, t2)
{'values_changed': {"root[0]['id']": {'new_value': 2, 'old_value': 1}, "root[0]['value'][0]": {'new_value': 7, 'old_value': 1}, "root[1]['id']": {'new_value': 3, 'old_value': 2}, "root[2]['id']": {'new_value': 1, 'old_value': 3}, "root[2]['value'][0]": {'new_value': 1, 'old_value': 7}}, 'iterable_item_added': {"root[0]['value'][1]": 8}, 'iterable_item_removed': {"root[2]['value'][1]": 8}}

As you can see the results are different. Now items with the same ids are compared with each other.

>>> def compare_func(x, y, level=None):
...     try:
...         return x['id'] == y['id']
...     except Exception:
...         raise CannotCompare() from None
...
>>> DeepDiff(t1, t2, iterable_compare_func=compare_func)
{'iterable_item_added': {"root[2]['value'][2]": 1}, 'iterable_item_removed': {"root[1]['value'][2]": 1}}

If we set the verbose_level=2, we can see more details.

>>> DeepDiff(t1, t2, iterable_compare_func=compare_func, verbose_level=2)
{'iterable_item_added': {"root[2]['value'][2]": 1}, 'iterable_item_removed': {"root[1]['value'][2]": 1}, 'iterable_item_moved': {'root[0]': {'new_path': 'root[2]', 'value': {'id': 1, 'value': [1]}}, 'root[1]': {'new_path': 'root[0]', 'value': {'id': 2, 'value': [7, 8]}}, 'root[2]': {'new_path': 'root[1]', 'value': {'id': 3, 'value': [7, 8, 1]}}}}

We can also use the level parameter. Levels are explained in the Tree View.

For example you could use the level object to further determine if the 2 objects should be matches or not.

>>> t1 = {
...     'path1': [],
...     'path2': [
...         {
...             'id': 1,
...             'value': [1]
...         },
...         {
...             'id': 2,
...             'value': [7, 8, 1]
...         },
...     ]
... }
>>>
>>> t2 = {
...     'path1': [{'pizza'}],
...     'path2': [
...         {
...             'id': 2,
...             'value': [7, 8, 1]
...         },
...         {
...             'id': 1,
...             'value': [1, 2]
...         },
...     ]
... }
>>>
>>>
>>> def compare_func2(x, y, level):
...     if (not isinstance(x, dict) or not isinstance(y, dict)):
...         raise CannotCompare
...     if(level.path() == "root['path2']"):
...         if (x["id"] == y["id"]):
...             return True
...         return False
...
>>>
>>> DeepDiff(t1, t2, iterable_compare_func=compare_func2)
{'iterable_item_added': {"root['path1'][0]": {'pizza'}, "root['path2'][0]['value'][1]": 2}}

Note

The level parameter of the iterable_compare_func is only used when ignore_order=False which is the default value for ignore_order.

Back to DeepDiff 5.5.0 documentation!