2

In the following code that I wrote, n = 4, and so there are five if statements, so if I would like to increase n to be, say 10, then there will be a lot of if's. Therefore my question: how can I replace all the if statements with something more elegant?

n, p = 4, .5  # number of trials, probability of each trial
s = np.random.binomial(n, p, 100)
# result of flipping a coin 10 times, tested 1000 times.

d = {"0" : 0, "1" : 0, "2" : 0, "3" : 0, "4" : 0 }

for i in s:
    if i == 0:
        d["0"] += 1
    if i == 1:
        d["1"] += 1 
    if i == 2:
        d["2"] += 1    
    if i == 3:
        d["3"] += 1
    if i == 4:
        d["4"] += 1

I tried using nested for loops,

 for i in s:
     for j in range(0,5):
         if i == j:
             d["j"] += 1

But i get this error:

d["j"] += 1

KeyError: 'j'
3
  • I'm assuming your indenting is off? Commented Dec 28, 2017 at 23:20
  • 4
    Why in the world are you using strings as keys in your dictionary? This would be so much easier using integer keys, or even a list. Commented Dec 28, 2017 at 23:20
  • The "j" you use is the string "j", not the actual number you want. Hence why it says keyerror. Commented Dec 28, 2017 at 23:21

4 Answers 4

7

You could use collections.Counter with a comprehension:

from collections import Counter

Counter(str(i) for i in s)

Counter works here because you're incrementing by one. However if you want it more general you could also use collections.defaultdict:

from collections import defaultdict

dd = defaultdict(int)   # use int as factory - this will generate 0s for missing entries
for i in s:
    dd[str(i)] += 1  # but you could also use += 2 or whatever here.

or if you want it as plain dictionary, wrap it inside a dict call, for example:

dict(Counter(str(i) for i in s))

Both avoid KeyErrors when the key isn't present yet and you avoid the double loop.


As a side note: If you want plain dicts you could also use dict.get:

d = {}  # empty dict
for i in d:
    d[str(i)] = d.get(str(i), 0) + 1

However Counter and defaultdict behave almost like plain dictionaries so there's almost no need for this last one, because it is (probably) slower and in my opinion less readable.

Sign up to request clarification or add additional context in comments.

3 Comments

here you would usually just use d.get, no?
Note, you could use a Counter there as well, counts = Counter(), then loop and counts[str(j)] += 1` no need to handle missing values..
@juanpa.arrivillaga Yeah dict.get is much smarter here - I've edited it. Thanks!
7

You need to convert the integer to a string in the loop.

for i in s:
    for j in range(0,5):
        if i == j:
            d[str(j)] += 1

Comments

6

Alternatively to Miket25's answer, you can actually use numbers as dictionary keys, like:

d = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0 }

for i in s:
    # 0 <= i < 5 is the same as looking through and checking
    # all values 0-4 but more efficient and cleaner.
    if 0 <= i < 5:
        d[i] += 1

Comments

1

You can try something like this without importing any external module:

In one line

import numpy as np
n, p = 4, .5  # number of trials, probability of each trial
s = np.random.binomial(n, p, 100)
# result of flipping a coin 10 times, tested 1000 times.

d = {"0" : 0, "1" : 0, "2" : 0, "3" : 0, "4" : 0 }


[d.__setitem__(str(i),d[str(i)]+1) for i in s  for j in range(0, 5) if str(i) in d]



print(d)

output: (as it is random so can be anything)

{'1': 22, '3': 23, '0': 3, '4': 6, '2': 46}

Detailed solution:

for i in s:
    for j in range(0, 5):
        if str(i) in d:
            d[str(i)]+=1

print(d)

output:

{'4': 6, '0': 6, '3': 29, '1': 25, '2': 34}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.