GAP2002
GAP2002

Reputation: 979

How to create a set of dictionary keys from an array of dictionaries

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

Answers (2)

ShadowRanger
ShadowRanger

Reputation: 155428

You can make one of two tiny changes to make what you've written work:

  1. 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 dicts 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.

  2. 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

Prune
Prune

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

Related Questions