You could use a list comprehension that checks if elements from a1 exist in the set version of a2. Since lists are not hashable, we can use tuples instead.
# Convert a2 elements to a set of tuples
a2_set = {tuple(sublst) for sublst in a2}
# Use a list comprehension to filter the elements from a1 that don't exist in a2
difference = [sublst for sublst in a1 if tuple(sublst) not in a2_set]
print(difference)
Output:
[[1, 4], [2, 5], [3, 6], [4, 7], [5, 8], [6, 9]]
If we don't care about order(sets are unordered), we can convert a1 and a2 to sets of tuples and apply set difference using a - b or a.difference(b):
print(a1_set - a2_set)
# {(5, 8), (1, 4), (3, 6), (2, 5), (6, 9), (4, 7)}
print(a1_set.difference(a2_set))
# {(5, 8), (1, 4), (3, 6), (2, 5), (6, 9), (4, 7)}
We could also turn these results into nested lists using list comprehensions:
print([list(tup) for tup in a1_set - a2_set])
# [[5, 8], [1, 4], [3, 6], [2, 5], [6, 9], [4, 7]]
print([list(tup) for tup in a1_set.difference(a2_set)])
# [[5, 8], [1, 4], [3, 6], [2, 5], [6, 9], [4, 7]]
However if you want the symmetric difference, as explained in the docs:
Return a new set with elements in either the set or other but not both.
We can calculate the symmetric difference using either a ^ b or a.symmetric_difference(b):
a1_set = {tuple(sublst) for sublst in a1}
a2_set = {tuple(sublst) for sublst in a2}
print(a1_set ^ a2_set)
# {(5, 8), (6, 9), (1, 4), (4, 7), (3, 6), (2, 5)}
print(a1_set.symmetric_difference(a2_set))
# {(5, 8), (6, 9), (1, 4), (4, 7), (3, 6), (2, 5)}
Which can also be converted from a set of tuples to nested using list comprehensions:
print([list(tup) for tup in a1_set ^ a2_set])
# [[5, 8], [6, 9], [1, 4], [4, 7], [3, 6], [2, 5]]
print([list(tup) for tup in a1_set.symmetric_difference(a2_set)])
# [[5, 8], [6, 9], [1, 4], [4, 7], [3, 6], [2, 5]]