Reputation: 2573
If we have
X1=[[a,b,c],[a,e,t],[a,b,c]]
and
X2=[[a,b,c]]
I want to find the difference between X1 and X2 which is:
X3=X1-X2=[[a,b,c],[a,e,t]].
So my output should contain two lists not one as I only want to remove one [a,b,c] not both.
I am doing it in this way but I get error:
s = set(X2)
X3 = [x for x in X1 if x not in s]
The error I get is this:
unhashable type: 'list'
I get this error when the program get to this point:
s = set(X2)
Upvotes: 1
Views: 132
Reputation: 78556
lists are unhashable so they cannot be members of a set
. You can convert the inner lists into a frozenset
, so two sublists with the same items but different ordering are still considered same and then use a Counter
to find the difference between both lists:
from collections import Counter
X3 = Counter([frozenset(i) for i in X1]) - Counter([frozenset(i) for i in X2])
print(X3)
# Counter({frozenset({'c', 'a', 'b'}): 1, frozenset({'e', 'a', 't'}): 1})
print(X3.keys())
# [frozenset({'e', 't', 'a'}), frozenset({'c', 'b', 'a'})]
A Counter
is a subclass of a dict
, so you can return the difference as a list by using .keys()
:
print(X3.keys()) # or print(list(X3.keys())) in Python 3.x
# [frozenset({'e', 't', 'a'}), frozenset({'c', 'b', 'a'})]
If you need to keep your inner list
s, you can replace the frozenset
with lists by doing:
X3 = [list(i) for i in X3.keys()]
print(X3)
# [['a', 't', 'e'], ['c', 'a', 'b']]
Upvotes: 1
Reputation: 386
So, X3 = [a,e,t]
, right?
There is no need to convert it to set. You can do this:
result = [x for x in X1 if x not in X2]
.
Upvotes: 4
Reputation: 298186
As the error states, lists are unhashable (because they're mutable). Convert your list of lists into a list of tuples, which are hashable:
>>> hash((1, 2, 3))
2528502973977326415
>>> hash([1, 2, 3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
In your case, you could do:
s = set(map(tuple, X2))
Upvotes: 0