2

I have a dictionary which looks like:

dict = {'A':[1,2], 'B':[0], 'c':[4]}

need it to look like:

dict = {'A':[1,2], 'B':[0,0], 'c':[4,0]}

What I am doing right now:

dict = {x: y+[0] for (x,y) in dict.items() if len(y) < 2}

which generates:

dict = {'B':[0,0], 'c':[4,0]}

any idea how I could avoid eliminating those who do not meet the condition?

martineau
  • 119,623
  • 25
  • 170
  • 301
ahajib
  • 12,838
  • 29
  • 79
  • 120

6 Answers6

3

You're almost there. Try:

my_dict = {x: y + [0] if len(y) < 2 else y
           for (x,y) in dict.items()}

(as mentioned by jp_data_analysis, avoid naming variables after builtins like dict)

Phydeaux
  • 2,795
  • 3
  • 17
  • 35
2

This is one way.

Note: do not name variables after classes, e.g. use d instead of dict.

d = {'A':[1,2], 'B':[0], 'c':[4]}

d = {k: v if len(v)==2 else v+[0] for k, v in d.items()}

# {'A': [1, 2], 'B': [0, 0], 'c': [4, 0]}
jpp
  • 159,742
  • 34
  • 281
  • 339
2

You can use dictionary comprehension:

d = {'A':[1,2], 'B':[0], 'c':[4]}
new_d = {a:b+[0] if len(b) == 1 else b for a, b in d.items()}

Also, it is best practice not to assign variables to names shadowing common builtins, such as dict, as you are then overriding the function in the current namespace.

Ajax1234
  • 69,937
  • 8
  • 61
  • 102
2
  1. Your code is almost correct. Your problem is that you're filtering out any lists bigger than 2. What you need to do instead is simply place them in the new dictionary unchanged. This can be done using the ternary operator. It has the form value1 if condition else value2.

  2. Also, if you want a more general way to pad every list in your dictionary to be of equal length, you can use map and max.

Here is your code with the above modifications:

>>> d = {'A':[1, 2], 'B': [0], 'c': [4]}
>>> 
>>> max_len = max(map(len, d.values()))
>>> {k: v + [0] * (max_len - len(v)) if len(v) < max_len else v for k, v in d.items()}
{'A': [1, 2], 'B': [0, 0], 'c': [4, 0]}
>>> 
Christian Dean
  • 22,138
  • 7
  • 54
  • 87
  • Worth pointing out that in 3.5+ you can also combine lists as follows: `{k: [*v, *[0 for i in range(max_len-len(v))]] if len(v) < max_len else v for k, v in d.items()}` – ZaxR Feb 15 '18 at 16:25
  • @ZaxR Yep sure, but I'm pretty sure that'd be slower than just list multiplication and concatenation. – Christian Dean Feb 15 '18 at 16:26
  • Looking at [this analysis](https://stackoverflow.com/a/35631185/7619676) of unpacking, it seems like it might actually be faster, but I haven't really dug very deep on it. – ZaxR Feb 15 '18 at 16:32
1

A generalized way:

d = {'A':[1,2], 'B':[0], 'c':[4]}

m = max(len(v) for v in d.values())
for k, v in d.items():
    if len(v) < m:
        d[k].extend([0 for i in range(m-len(v))])
ZaxR
  • 4,896
  • 4
  • 23
  • 42
0

You were very close, just use update():

d = {'A':[1,2], 'B':[0], 'c':[4]}

d.update({x: y+[0] for (x,y) in d.items() if len(y) < 2})

d
# {'A': [1, 2], 'B': [0, 0], 'c': [4, 0]}

Like others have said, don't use reassign reserved names like dict, it's a one way street down to debugging hell.

r.ook
  • 13,466
  • 2
  • 22
  • 39
  • To whomever downvoted this answer, can you please explain your rationale so I can improve it necessary? This code works and answers the question, so I'm not sure why it attracted the downvote. – r.ook Feb 15 '18 at 16:12
  • I actually like your answer too but would be interested to know the downvoters idea on this. – ahajib Feb 15 '18 at 16:14