Suppose I want to create a dictionary that maps digits to numbers less than 100 ending in those digits as follows:
d = {}
for i in range(100):
r = i % 10
if r in d:
d[r] = d[r].append(i)
else:
d[r] = [i]
print d
First of all, when i is 20, d[r] is apparently a NoneType when I try to append to it, throwing an error. Why would this be? Secondly, I feel like my approach is inefficient, as the work in checking if r in d isn’t propagated. Something like this would be better, I feel:
case(d[r]) of
SOME(L) => d[r] = L.append(i)
| NONE => d[r] = [i]
Is there a way to have that logic in python?
This is because the following code is wrong:
.appendmodifies the list as a side effect, and returnsNone. So after the list is appended to, it gets thrown away and replaced with theNonevalue now being re-assigned intod[r].There are a variety of hacks that can be used, but none of them are appropriate here.
Instead, solve the specific problem: “modify a dictionary value if present, or create a new value otherwise”. This can be refined into “create an empty default value if absent, and then modify the value now guaranteed to be present”.
You can do that using
.setdefault, or more elegantly, you can replace the dictionary with acollections.defaultdict:Or you can solve the even more specific problem: “create a dictionary with a given pattern”, i.e. from applying a rule or formula to an input sequence (in this case, the input is
range(100):Or you can solve the even more specific problem, by taking advantage of the fact that
rangetakes another argument to specify a step size: