Organize code in functions. This is the most important point. Make it a
personal rule to put all code in functions. It's easy to do, even if you don't
fully appreciate all of the benefits yet. But with that simple rule in place,
you now have a mechanism to organize the code better.
When feasible, do one thing at a time. Don't generate data (eg, flip coins)
and try to perform multiple kinds of data analysis (counting head/tails,
counting streaks, etc) at the same time. It's too much complexity. Break things
down. For example, one function can focus solely on generating the coin flips.
from random import randint
def coin_flips(n):
return [randint(0, 1) for _ in range(n)]
If you need to count things, consider using a Counter
. Super easy.
from collections import Counter
def tally_flips(flips):
return Counter(flips)
If you need to group things, consider using groupby
. If given no argument
other than data values, groupby()
will organize the data based on equality –
exactly what you need to find streaks of any size.
from itertools import groupby
def find_streaks(flips):
return [list(group) for _, group in groupby(flips)]
Find just the big streaks. That's just another function.
def find_big_streaks(streaks, size = 3):
return [s for s in streaks if len(s) >= size]
Orchestration. Again, another function.
import sys
def main(args):
flips = coin_flips(20)
tally = tally_flips(flips)
streaks = find_streaks(flips)
bigs = find_big_streaks(streaks)
print(flips, tally, streaks, bigs, sep = '\n')
if __name__ == '__main__':
main(sys.argv[1:])
Should one really make such tiny functions? Maybe not. It depends on the
context. Will you need to re-use any of the functionality somewhere else in the
program? If so, a separate function, even a tiny one, can be a good idea.
If not, it might make more sense to ditch the function and move the single line
of code back to the calling location. If we do that in the case at hand, we end
up with the code below. Even though it contains only a single function, it
still retains the benefits of a functional mindset because we are taking
care to separate the tasks. It's very easy to read code like this because
each step is distinct, small, and simple.
def main(args):
flips = [randint(0, 1) for _ in range(20)]
tally = Counter(flips)
streaks = [list(group) for _, group in groupby(flips)]
bigs = [s for s in streaks if len(s) >= 3]
print(flips, tally, streaks, bigs, sep = '\n')