Salech Alhasov
Salech Alhasov

Reputation: 145

Replacing repeated if statements with nested for loops in python?

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'

Upvotes: 2

Views: 316

Answers (4)

Aaditya Ura
Aaditya Ura

Reputation: 12689

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}

Upvotes: 1

MSeifert
MSeifert

Reputation: 152840

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.

Upvotes: 7

SCB
SCB

Reputation: 6149

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

Upvotes: 6

Miket25
Miket25

Reputation: 1913

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

Upvotes: 7

Related Questions