Mayank Jain
Mayank Jain

Reputation: 1077

set of list of lists in python

I am having a list of lists :

mat = [[1,2,3],[4,5,6],[1,2,3],[7,8,9],[4,5,6]]

and I want to convert into a set i.e. remove the repeating lists and creating a new list out of it which will only contain the unique lists.

In above case the required answer will be

[[1,2,3],[4,5,6],[7,8,9]]

But when I do set(mat), it gives me error

TypeError: unhashable type: 'list'

Can you please solve my problem. Thanks in advance!

Upvotes: 46

Views: 51773

Answers (4)

Punit Vara
Punit Vara

Reputation: 4194

List as key for dictionary or set is not valid. Because key should remain constant when we want to access values in dictionary for example. Values can change but keys always remain constant.

So in your case:

mat = [[1,2,3],[4,5,6],[1,2,3],[7,8,9],[4,5,6]]

We need to convert inner list to tuple. It can be done by

map(tuple, mat)

Now tuple can be used as key for set/dictionary because tuple's key cannot be changed.

dict.fromkeys(map(tuple, mat))

Since we need final answer as list of list we need to convert all tuple keys of dictionary as list. We don't care about values so we only read keys from dictionary and convert it to list.

   mat = map(list, dict.fromkeys(map(tuple, mat)).keys())

Now mat would look something like this.

mat = [[1,2,3],[4,5,6],[7,8,9]]

In Python 3.8+ dictionary will preserve order for older version, OrderedDict can be used.

Upvotes: 0

Abhijit
Abhijit

Reputation: 63707

@thefourtheye's answer clearly depicts the problem you were facing with non-hashable data types and the way to by pass it so that you can create a set and remove duplicates. This should suffice for most of thef problems but, re-reading your question

In above case the required answer will be [[1,2,3],[4,5,6],[7,8,9]].

If the order is important, you need to use OrderedDict

>>> from collections import OrderedDict
>>> map(list, OrderedDict.fromkeys(map(tuple, mat)).keys())
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Upvotes: 6

thefourtheye
thefourtheye

Reputation: 239443

Since the lists are mutable, they cannot be hashed. The best bet is to convert them to a tuple and form a set, like this

>>> mat = [[1,2,3],[4,5,6],[1,2,3],[7,8,9],[4,5,6]]
>>> set(tuple(row) for row in mat)
set([(4, 5, 6), (7, 8, 9), (1, 2, 3)])

We iterate through the mat, one list at a time, convert that to a tuple (which is immutable, so sets are cool with them) and the generator is sent to the set function.

If you want the result as list of lists, you can extend the same, by converting the result of set function call, to lists, like this

>>> [list(item) for item in set(tuple(row) for row in mat)]
[[4, 5, 6], [7, 8, 9], [1, 2, 3]]

Upvotes: 60

inspectorG4dget
inspectorG4dget

Reputation: 113915

Lists are mutable, therefore unhashable. Use tuples instead

In [114]: mat = [[1,2,3],[4,5,6],[1,2,3],[7,8,9],[4,5,6]]

In [115]: mat = [tuple(t) for t in mat]

In [116]: matset = set(mat)

In [117]: matset
Out[117]: {(1, 2, 3), (4, 5, 6), (7, 8, 9)}

In [118]: [list(t) for t in matset]
Out[118]: [[4, 5, 6], [7, 8, 9], [1, 2, 3]]

Upvotes: 8

Related Questions