0

So I have this exercise to do: Write a program to find out how often a streak of six heads or a streak of six tails comes up in a randomly generated list of head and tails and if there is a streak you add to to the variable number_of_streaks

I made the loop for adding H and T to the list but I don't know how to check if there is a streak in that list. I tried this code:

if th[experiment_number][z] == th[experiment_number][z+1]:

but I get this error: IndexError: string index out of range

(Note I am new to programming, I am still learning)

import random


number_of_streaks = 0
th = []
for  experiment_number in range(10000):
    for x in range(100):
        if random.randint(0, 1):
            th.append('H')
        else:
            th.append('T')
    first = 0
    last = 5
    for x in range(100):
        for z in range (6):
            if th[experiment_number][z] == th[experiment_number][z+1]:
                number_of_streaks += 1

  • Do you want to use `experiment_number` or `x` as your index in your arrays in the for loop? – FCo Jul 21 '22 at 20:58
  • 1. you could use a string instead of a list and then use a regex approach or 2. check equality of slices of size 8 (to be sure to have 6 consecutives) – cards Jul 21 '22 at 20:59
  • 1) `th = []` should be move to be within the outer for loop, 2) th is 1 dimensional so `th[experiment_number][z]...` is erroneous. – DarrylG Jul 21 '22 at 21:00
  • @cards I'm curious about 2., can't imagine what you mean ... – Kelly Bundy Jul 21 '22 at 21:07
  • @Kelly Bundy given list of random `H` and `T` then move though it with slices. Size could be 8 for non-boundary checks and 7 otherwise. The "extra" size is due to ensure the exactness of the sequence – cards Jul 21 '22 at 21:17
  • @cards What do you do with the slices? – Kelly Bundy Jul 21 '22 at 21:24
  • Assume the experiment of 7 outcomes all equals, `res = "H"*7`, if you move with a slice of 6, `res[:6]` is correct, with `res[1:7]` is correct but you get a false positive. To avoid that embed the sequence into a bigger slice – cards Jul 21 '22 at 21:31
  • @cards Ah, you think that doesn't contain a string of six heads. Given the [context](https://automatetheboringstuff.com/2e/chapter4/) of identifying humans, I'd say that interpretation is wrong. – Kelly Bundy Jul 21 '22 at 21:47
  • @Kelly Bundy than it is even easier... less think to take care! I would say is ambigous – cards Jul 21 '22 at 21:57
  • 1
    @cards Yes, still ambiguous, although I'm strongly leaning towards the other interpretation. They say humans tend to make up "alternating head-tail results like H T H T H H T H T T", and that six consecutive equals indicates non-human. With that in mind, seven or more consecutive equals also indicates non-human. Even more so. So we should include that. But yeah, I wish the book had made it real clear. It does have answers for the practice questions but apparently not for the projects, so we can't judge by that, either. – Kelly Bundy Jul 21 '22 at 22:10

3 Answers3

0

Walk the list, and keep a count of the length of the current streak. If the current item is equal to the previous item, increase the length. Otherwise, reset the counter to 0. When the counter reaches 6, you've found a streak.

chepner
  • 497,756
  • 71
  • 530
  • 681
0

The first half of your code works, the second half doesn't.

This code should work:

# The number of consecutive Heads or Tails needed to form a streak
streak_num = 6
# Iterate over the list th, excluding the last 5 (streak_num-1) elements of the list
for n in range(0,len(th)-streak_num+1):
    # Create a list to append values to
    list = []
    # Iterate streak_num times to check for a streak
    for m in range(0,streak_num):
        # Starting from the nth element in the list
        # Append that nth element to the list and the next streak_num-1 elements to the list
        list.append(th[n+m])
    # Check to see if all elements in list are the same
    if len(set(list)) == 1:
        # If they are all the same, a streak of size streak_num has been found
        # Therefore add it the count
        number_of_streaks = number_of_streaks + 1
    

The part you're having trouble with is the following portion:

# Iterate over the list th, excluding the last 5 (streak_num-1) elements of the list
for n in range(0,len(th)-streak_num+1):

If you are looking for a streak of 6, you have to stop checking the list the 6th last element.

Let me know if you have any questions.

gphull
  • 78
  • 5
  • Okay but why do i need to exclude the last 5 elements of that list? – GabiTomoiaga Jul 22 '22 at 19:48
  • You don't exclude the last five elements of the list, you stop iterating on the last five elements of the list. My for loops look forward to the next 6 elements. If I'm on the second last element of the list, and I try to look ahead 6 elements I get the error message you received "IndexError: string index out of range". This is because there are no 6 elements past the second last element. There are only two more, so the code errors out. Therefore, the loop finishes iterating on the 6th last element, and looks forward to the next 5, completing the search for streaks of 6. – gphull Jul 23 '22 at 18:03
0

Assumed that a streak is described as the least amount of consecutive identical outcomes. So, if it is 6 then a streak can be made of 6, 7, 8, ... outcomes.

from itertools import groupby
from collections import Counter
import random

# initialize the random number generator - for testing!
random.seed(121)

n_throws = 100
streak_threshold = 6 # exact value or more
outcomes = 'HT'

# flip the coin
experiment = [outcomes[random.randint(0, 1)] for _ in range(n_throws)]

# streaks ids
grps_by_streak = [grp_id for grp_id, grp in groupby(experiment) if len(list(grp)) >= streak_threshold]
print(grps_by_streak)
#['H', 'H', 'T']

# frequency for each result
cc = Counter(grps_by_ streak)
print(cc)
#Counter({'H': 2, 'T': 1})

number_of_streaks = sum(cc.values())
print(number_of_streaks)
#3

If a streak is not a threshold value but an exact one just smalls fixed are needed:

  • replace streak_threshold = 6 to streak = 6 (just for consistency)
  • use equality and change of variable: grps_by_streak = [grp_id for grp_id, grp in groupby(experiment) if len(list(grp)) == streak]
cards
  • 3,936
  • 1
  • 7
  • 25
  • okay thx but i dont what this code is doing! Seems rocket science to me :)) – GabiTomoiaga Jul 22 '22 at 19:46
  • the code should be self-explained (hope so), follow the comments. With [_groupby_](https://docs.python.org/3/library/itertools.html#itertools.groupby) you create groups (lists) of consecutive outcomes which are then filtered by their length. [_Counter_](https://docs.python.org/3/library/collections.html#counter-objects) is used to get the frequency of **each** such outcome then sum all outcomes together. Maybe try to use different seeds to get different results... – cards Jul 22 '22 at 23:09