Polly
Polly

Reputation: 1097

Adding missing keys in dictionary in Python

I have a list of dictionaries:

L = [{0:1,1:7,2:3,4:8},{0:3,2:6},{1:2,4:6}....{0:2,3:2}]. 

As you can see, the dictionaries have different length. What I need is to add missing keys:values to every dictionary to make them being with the same length:

L1 = [{0:1,1:7,2:3,4:8},{0:3,1:0,2:6,3:0,4:0},{0:0, 1:2,3:0,4:6}....{0:2,1:0,2:0,3:2,4:0}], 

Means to add zeros for missing values. The maximum length isn't given in advance, so one may get it only iterating through the list.

I tried to make something with defaultdicts, like L1 = defaultdict(L) but it seems I don't understand properly how does it work.

Upvotes: 5

Views: 11912

Answers (6)

Martijn Pieters
Martijn Pieters

Reputation: 1124110

You'll have to make two passes: 1 to get the union of all keys, and another to add the missing keys:

max_key = max(max(d) for d in L)
empty = dict.fromkeys(range(max_key + 1), 0)
L1 = [dict(empty, **d) for d in L]

This uses an 'empty' dictionary as a base to quickly produce all keys; a new copy of this dictionary plus an original dictionary produces the output you want.

Note that this assumes your keys are always sequential. If they are not, you can produce the union of all existing keys instead:

empty = dict.fromkeys(set().union(*L), 0)
L1 = [dict(empty, **d) for d in L]

Demo:

>>> L = [{0: 1, 1: 7, 2: 3, 4: 8}, {0: 3, 2: 6}, {1: 2, 4: 6}, {0: 2, 3: 2}]
>>> max_key = max(max(d) for d in L)
>>> empty = dict.fromkeys(range(max_key + 1), 0)
>>> [dict(empty, **d) for d in L]
[{0: 1, 1: 7, 2: 3, 3: 0, 4: 8}, {0: 3, 1: 0, 2: 6, 3: 0, 4: 0}, {0: 0, 1: 2, 2: 0, 3: 0, 4: 6}, {0: 2, 1: 0, 2: 0, 3: 2, 4: 0}]

or the set approach:

>>> empty = dict.fromkeys(set().union(*L), 0)
>>> [dict(empty, **d) for d in L]
[{0: 1, 1: 7, 2: 3, 3: 0, 4: 8}, {0: 3, 1: 0, 2: 6, 3: 0, 4: 0}, {0: 0, 1: 2, 2: 0, 3: 0, 4: 6}, {0: 2, 1: 0, 2: 0, 3: 2, 4: 0}]

The above approach to merge two dictionaries into a new one with dict(d1, **d2) always works in Python 2. In Python 3 additional constraints have been set on what kind of keys you can use this trick with; only string keys are allowed for the second dictionary. For this example, where you have numeric keys, but you can use dictionary unpacking instead:

{**empty, **d}  # Python 3 dictionary unpacking

That'll work in Python 3.5 and newer.

Upvotes: 8

n1nj4
n1nj4

Reputation: 526

This is quick and slim:

missing_keys = set(dict1.keys()) - set(dict2.keys())
for k in missing_keys:
    dict1[k] = dict2[k]

Upvotes: 1

Cobry
Cobry

Reputation: 4548

Unless None is a valid value for a dictionary key you have herein is a great solution for you

L = [{0: 1, 1: 7, 2: 3, 4: 8}, {0: 3, 2: 6}, {1: 2, 4: 6}, {0: 2, 3: 2}]
for i0, d0 in enumerate(L[:-1]):
    for d1 in L[i0:]:
        _ = [d0.__setitem__(k,d1[k]) for k in d1 if d0.get(k,None) is None]
        _ = [d1.__setitem__(k,d0[k]) for k in d0 if d1.get(k,None) is None]

print(L)
>>> [{0: 1, 1: 7, 2: 3, 3: 2, 4: 8}, {0: 3, 1: 2, 2: 6, 3: 2, 4: 6}, {0: 2, 1: 2, 2: 3, 3: 2, 4: 6}, {0: 2, 1: 7, 2: 3, 3: 2, 4: 8}]

Upvotes: 0

Ayush
Ayush

Reputation: 3955

a bit of caution: changes L

>>> allkeys = frozenset().union(*L)
>>> for i in L:
...    for j in allkeys:
...        if j not in i:
...            i[j]=0

>>> L
[{0: 1, 1: 7, 2: 3, 3: 0, 4: 8}, {0: 3, 1: 0, 2: 6, 3: 0, 4: 0}, {0: 0, 1: 2, 2:
 0, 3: 0, 4: 6}, {0: 2, 1: 0, 2: 0, 3: 2, 4: 0}]

Upvotes: 3

elzell
elzell

Reputation: 2306

Maybe not the most elegant solution, but should be working:

L = [{0:1,1:7,2:3,4:8},{0:3,2:6},{1:2,4:6},{0:2,3:2}]

alldicts = {}
for d in L:
    alldicts.update(d)

allkeys = alldicts.keys()

for d in L:
    for key in allkeys:
        if key not in d:
            d[key] = 0

print(L)

Upvotes: 3

El'endia Starman
El'endia Starman

Reputation: 2244

This is only a solution, but I think it's simple and straightforward. Note that it modifies the dictionaries in place, so if you want them to be copied, let me know and I'll revise accordingly.

keys_seen = []
for D in L:  #loop through the list
    for key in D.keys():  #loop through each dictionary's keys
        if key not in keys_seen:  #if we haven't seen this key before, then...
            keys_seen.append(key)  #add it to the list of keys seen

for D1 in L:  #loop through the list again
    for key in keys_seen:  #loop through the list of keys that we've seen
        if key not in D1:  #if the dictionary is missing that key, then...
            D1[key] = 0  #add it and set it to 0

Upvotes: 2

Related Questions