Reputation: 979
I have a dictonary like so:
{
"x": {
"a": 1,
"b": 2,
"c": 3
},
"y": {
"a": 1,
"b": 2,
"d": 4
}
}
The values of each key are a dictionary. I want to create a set
of all the keys of these dictionaries so like in the example above:
{"a", "b", "c", "d"}
I have spent a long time on this but always end up with the error: TypeError: unhashable type: 'dict_keys'
.
My code at the moment is:
set(item.keys() for item in [dictonary for dictonary in self.data.values()])
Ideally, I don't want to use any modules but if needs must I will.
Upvotes: 1
Views: 3593
Reputation: 155428
You can make one of two tiny changes to make what you've written work:
Union the keys
objects (and remove the pointless no-op inner listcomp):
set().union(*[dictionary.keys() for dictionary in self.data.values()])
# Or somewhat less obviously, but more efficiently, you can just union
# the dicts themselves, which already act as collections of their keys:
set().union(*self.data.values())
This makes an empty set, then unpacks all the keys views (or the dict
s themselves) as positional arguments to union with it; set.union
takes varargs, so you can pass it any number of collections to union together at once.
Correctly use nested loops in a single comprehension, not a comprehension nested inside another (that doesn't unpack the way you were likely expecting):
set(item for dictionary in self.data.values() for item in dictionary)
# Or slightly better, but not as close to what you wrote, a true set comprehension
{item for dictionary in self.data.values() for item in dictionary}
Note the order of the looped things is different; the left-most loop in such a multiloop comprehension is the outer loop, moving to inner loops as you go to the right.
Upvotes: 5
Reputation: 77857
Your immediate problem is that you tried to add the list of keys to your set.
This would have resulted in the set {['a', 'b', 'c'], ['a', 'b', 'd']}
, except that you cannot put a mutable element into a set (unhashable).
Instead, you need to iterate through those keys and get them into the set individually.
Also note that [dictionary for dictionary in self.data.values()]
is better expressed as list(self.data.values())
.
src = {
"x": {
"a": 1,
"b": 2,
"c": 3
},
"y": {
"a": 1,
"b": 2,
"d": 4
}
}
result = set(key for item in src.values() for key in item.keys())
print(result)
Upvotes: 4