2025, Nov 11 23:00
How to compare two Python lists of NumPy arrays as unordered collections without errors
Learn a safe way to compare two Python lists of NumPy arrays ignoring order. Avoid unhashable ndarray and ambiguous truth value errors by using tuple sets.
Checking whether two Python lists contain the same NumPy arrays, regardless of order, sounds straightforward until you try the obvious tools. Sets don’t work because numpy.ndarray is unhashable, and even a simple membership test with in blows up due to NumPy’s elementwise semantics. Let’s walk through why this happens and how to compare such collections safely and predictably.
Problem setup
We want the comparison to ignore the order of arrays in the outer lists, but preserve the order of elements inside each individual array. For instance, two lists like these should be considered equal:
import numpy as np
arrs_a = [np.array([1, 2]), np.array([3])]
arrs_b = [np.array([3]), np.array([1, 2])]
arrs_c = [np.array([2, 1]), np.array([3])]
At first glance, a direct membership-based approach looks fine, but it fails:
def compare_unsafely(lst_a, lst_b):
for block in lst_a:
if block not in lst_b:
return False
for block in lst_b:
if block not in lst_a:
return False
return True
# compare_unsafely(arrs_a, arrs_b) # raises at runtime
Running that membership test raises:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
And trying to use sets to ignore outer ordering fails even earlier:
TypeError: unhashable type: numpy.ndarray
Why it breaks
NumPy operators like == are vectorized: comparing arrays elementwise returns another array of booleans, not a single True/False. Python’s in operator relies on equality under the hood. When it tries to evaluate the result of an elementwise comparison in a boolean context, NumPy refuses and you get the ambiguous truth value error.
The set approach fails because numpy.ndarray is not hashable. Hash-based containers like set and dict need a stable hash; ndarray doesn’t provide one, so you get the unhashable type error.
The fix
The reliable way to make this comparison order-insensitive is to convert each array to a hashable, immutable representation of its contents, collect those into sets, and compare the sets. Tuples work well for this purpose. Flattening each array first ensures we’re comparing the actual sequence of values in a consistent linear form.
import numpy as np
def same_payloads(seq_a, seq_b):
pool_a = {tuple(item.flatten()) for item in seq_a}
pool_b = {tuple(obj.flatten()) for obj in seq_b}
return pool_a == pool_b
bags_1 = [np.array([1, 2]), np.array([3])]
bags_2 = [np.array([3]), np.array([1, 2])]
result = same_payloads(bags_1, bags_2)
print(result)
# True
This comparison ignores the order of arrays in the outer list, but the order within each array is preserved because tuples retain element order. For example, an array with values [2, 1] will not match [1, 2].
Why this matters
It’s easy to assume that Python membership checks and set operations will just work with NumPy arrays, but NumPy’s semantics are intentionally different. Relying on the default behavior leads to confusing errors instead of clear True/False outcomes. Converting arrays to tuples makes the intent explicit and the result deterministic.
Takeaways
If you need to compare two lists of NumPy arrays as unordered collections while keeping the order inside each array intact, first map each array to a tuple of its flattened values and then compare the resulting sets. This sidesteps both the ambiguous truth value problem and the unhashable ndarray issue without altering the original data.