There are two elements of your task: rounding, and taking the uniques.
If you want to have two numbers be considered "the same" if they differ by less than .01, that's rather difficult. Among other things, this is nontransitive; A can be "close" to B and B "close" to C, without A being "close" to C. In math terms, this isn't an equivalence relation. Since another way of saying "take only one of each set of close lists" is "take only one member of each equivalence class", that fact that this isn't an equivalence relation is a problem.
A subtly different, but more possible interpretation, is taking your problem statement as asking to round to two decimal places; this can be accomplished with
decimal_points = 2
rounded_tuples = [tuple(tuple(round(element, decimal_points) for element in inner_list)
for inner_list in outer_list)
for outer_list in a]
Taking uniques is much more difficult. One method is to convert everything to a canonical member of its equivalence class, then take the set of all such members. This is why I have tuples above; taking the set requires non-mutable data structures such as tuples.
Now, rather than the equivalence relation being "close", it's "differ by a permutation".
With this equivalence relation, one way of getting a canonical member is to sort each list. But now the problem is that we have lists of lists, so we have to have some ordering of the sublists. A simple ordering is lexographical ordering: sort according to the first element, then among each list with the same first element, sort according to the second, etc.
def sort_nested_tuple(nested_tuple):
for i in range(len(nested_tuple[0])):
nested_tuple = tuple(sorted(nested_tuple, key = lambda x: x[i]))
return nested_tuple
sorted_tuples = [sort_nested_tuple(outer_tuple)
for outer_tuple in rounded_tuples]
Here, I'm going through each element and sorting by it. Since the last element is used as a key last, it overrides all previous keys. Only if two lists have the same last element is the ordering from the second to last element preserved. So this can be considered "little-endian" lexographical ordering, but it's not really important what ordering you have as long as it's consistent.
Now we just have to take the set of the resulting tuples:
uniques = set(sorted_tuples)
This results in a set of tuples, rather than numpy objects, but you can convert back if you want. Also, you're getting the canonical list, which likely is not any of the original lists, so if you want to have a result consisting of lists that appeared in the original input, you'll have to do more work for that. A somewhat brute force method would be:
unique_originals = []
for unique in uniques:
for original, sorted_tuple in zip(a, sorted_tuples):
if sorted_tuple == unique:
unique_originals.append(original)
break