1

I need to count how many times 'Eagle' appears 2 times in a row in random generated list. In case ['Eagle', 'Eagle', 'Eagle', 'Eagle'] it should count 2, not 3

import random
def HeadsOrTails(amo):
amo1 = []
Coin = ['Eagle', 'Tails']
for i in range(amo):
    amo1.append(random.choice(Coin))
return amo1

count = 0

for i in range(len(HeadsOrTails(30))):
    if HeadsOrTails(30)[i] == 'Eagle':
        if HeadsOrTails(30)[i] == HeadsOrTails(30)[i+1]:
            count += 1
    else:
        continue

print(HeadsOrTails(30))
print(f' Eagle repeats {count} times in the list')

For some reason it calculates amount of values wrongly

Максим
  • 113
  • 1
  • 1
  • 8
  • Using your for loop, if the current is eagle and the next is eagle, count and move `i` on by 2, otherwise move `i` on by 1. You can't move `i` on by one each time or you will count 3 for 4 eagles in a row – Caius Jard Apr 22 '22 at 07:57
  • 3
    You need to call your function `HeadsOrTails()` only once and store it into a variable. Since you call the function each time you want to use it, you have a different list of result everytime, so the count is completly random ! – Titouan L Apr 22 '22 at 07:58

6 Answers6

2

Use a while loop and increment the indexer upon a match:

def count2(l):
    i = 1
    count = 0
    while i < len(l):
        if l[i] == l[i-1] == 'Eagle': # if both values are "Eagle"
            count += 1  # increment the counter
            i += 1      # and skip a step (with below, equivalent to i += 2)
        i += 1          # increment to next step
    return count

Examples:

count2(['Eagle', 'Eagle', 'Eagle', 'Eagle'])
# 2

count2(['Eagle', 'Eagle', 'Eagle'])
# 1

count2(['Eagle', 'Eagle', 'Tails', 'Eagle'])
# 1

count2(['Eagle', 'Eagle'])
# 1

count2(['Eagle'])
# 0

count2([])
# 0
generalization (counting n successive values)

you can use slicing and comparison to a set:

def countn(l, n=2, match='Eagle'):
    i = n-1        # start at n-1 position
    count = 0
    while i < len(l):
        if set(l[i-n+1:i+1]) == {match}: # if all values of the slice are "match" (= consecutive match)
            count += 1    # increment counter
            i += n        # and skip n steps
        else:
            i += 1        # else, go to the next step
    return count

example:

countn(['Eagle', 'Eagle', 'Eagle', 'Eagle', 'Eagle', 'Eagle'], n=3)
# 2

countn(['Eagle', 'Eagle', 'Eagle', 'Eagle', 'Eagle'], n=3)
# 1

countn(['Eagle', 'Eagle', 'Eagle'], n=3)
# 1

countn(['Eagle', 'Eagle', 'Tails', 'Eagle'], n=3)
# 0

countn([], n=3)
# 0
mozway
  • 194,879
  • 13
  • 39
  • 75
1

You should generate the list only once.
If 2 adjacent items are both Eagle then you skip to 2 items, else you skip only one.

list_size = 30
my_list = heads_or_tails(list_size)
count = 0

i = 0
while i < list_size  -1:
    if my_list[i] == my_list[i+1] == 'Eagle':
        count +=1
        i +=2
    else:
        i +=1
print(count)
TDG
  • 5,909
  • 3
  • 30
  • 51
  • this is more or less the same as [mine](https://stackoverflow.com/a/71965405/16343464), just with a different indexing ;) – mozway Apr 22 '22 at 08:15
  • @mozway Great minds think alike, or in my case - I'm a slow typer, didn't see your answer before I've submitted mine :) – TDG Apr 22 '22 at 08:18
  • No problem, just making it explicit that it's actually the same ;) – mozway Apr 22 '22 at 08:19
0

When you do this HeadsOrTails(30), each time it will compute a new one. Then in order to do what you expect, call it once and store its result in a variable.

And your code doesn’t control the fact that we are in a group of more than 3. I added this.

import random


def heads_or_tails(amo):
    amo1 = []
    coin = ["Eagle", "Tails"]
    for i in range(amo):
        amo1.append(random.choice(coin))
    return amo1


my_head_or_tails = heads_or_tails(30)

count = 0
already_in_pair = False
for i in range(len(my_head_or_tails)):
    current_is_eagle = my_head_or_tails[i] == "Eagle"
    try:
        next_is_eagle = my_head_or_tails[i + 1] == "Eagle"
    except IndexError:
        next_is_eagle = False

    if current_is_eagle and next_is_eagle and not already_in_pair:
        count += 1
        already_in_pair = True
    else:
        already_in_pair = False


print(my_head_or_tails)
print(f" Eagle repeats {count} times in the list")
Floh
  • 745
  • 3
  • 16
  • NO! There is no reason to use try-except here. You should use exceptions only when there are things that you don't control, like file system permissions. Here you have total control over the list's size and the indices. – TDG Apr 22 '22 at 08:22
  • Pythonic way is not like this, from my understanding. Ask forgiveness not permission. https://stackoverflow.com/questions/12265451/ask-forgiveness-not-permission-explain For me it means that you don’t have to check if you are at the end of the list, but handle that edge case. Try/Except is good for edges cases. – Floh Apr 22 '22 at 08:24
  • Moreover, here, for is better in pythonic way if you consider that you know how many times you want to iterate (size of the list). But it’s true also that if you consider that you jump, you don’t know precisely the number of steps, and then while is good as well. – Floh Apr 22 '22 at 08:30
0

Once you've built the list of Heads and Tails you should iterate over it comparing the current element with the element one index position ahead. If they're the same (HEAD) then advance the index by 2 otherwise increment by 1.

Therefore:

import random

HEAD = 'Eagle'
TAIL = 'Tail'
PAIR = [HEAD, HEAD]
N = 30

def HeadsOrTails(n):
    return random.choices([HEAD, TAIL], k=n)

coins = HeadsOrTails(N)

i, c = 0, 0

while i < len(coins) - 1:
    if coins[i:i+2] == PAIR:
        c += 1
        i += 2
    else:
        i += 1

print(coins)
print(c)
DarkKnight
  • 19,739
  • 3
  • 6
  • 22
0

Yet another approach. Build a list of positions and then check if the position(s) are present within the list. Instead of a count we return the pos_list and print the length of that list.

import random


def heads_or_tails(amo):
    amo1 = []
    coin = ['Eagle', 'Tails']
    for i in range(amo):
        amo1.append(random.choice(coin))
    return amo1


def get_count(searchstr='Eagle'):
    pos = []
    _lst = heads_or_tails(10)
    for j in range(len(_lst)):
        try:
            if _lst[j] == searchstr and _lst[j+1] == searchstr:
                if j not in pos and j-1 not in pos:
                    pos.append(j)
            else:
                continue
        except IndexError:
            pass
    return _lst, pos, searchstr


search_list, pos_lst, search_str = get_count()
print(search_list)
print(f'{search_str} repeats {len(pos_lst)} times in the list')
Dan Green
  • 76
  • 4
-1
import numpy as np

lst = list(np.random.choice(['Eagle', 'Tails'], size=10))
print(lst)

count = 0
pt = ''
while len(lst):
    item = lst.pop(0)
    if pt == item and pt == 'Eagle':
        pt = ''
        count += 1
    else:
        pt = item
print(count)
Kang San Lee
  • 312
  • 2
  • 10