11. Count


#1

The link:
https://www.codecademy.com/courses/learn-python/lessons/practice-makes-perfect/exercises/count?action=lesson_resume&link_content_target=interstitial_lesson

Actually, it says that I passed the test, but I wanted to run it in any possibility.
It says that item can be another list, so I was eager to check it out.

Can you please help me out on how to solve this?
I want to add two lists, other shorter then the previous one and check how many times does the longer list contain the smaller one.

This one doesn’t work. I have no idea why.
I know it’s a bit messed up, but after hour of figuring I changed a lot of code, so…

def count(sequence, item):

  occurence_count = 0
  if type(item) is int or type(item) is float or \
  type(item) is str:
    for i in sequence:
      if i == item:
        occurence_count += 1
    return occurence_count

  elif type(item) is list:
    for a, b in zip(sequence, item):
      abcount = 0     *The count of matches*
      while abcount < len(item):   
        if a == b:
        abcount += 1
        break
      else:
        if abcount == len(item):
          occurence_count += 1

    return occurence_count
count([1,2,3,4,5,6,7], [1,2,3])

#2

The item you input may be an integer, string, float, or even another list, which means:

count([[1,2,3],[4,5,6,7]], [1,2,3])

now [1,2,3] must equal [1,2,3] which is easy to test, what you do goes much further.

for starters don’t use zip, look:

for a, b in zip([1,2,3,4,5,6,7], [1,2,3]):
  print a, b

zip() ends one of the lists is completed, so if you want to do:

count([1,2,3,4,5,6,7], [4,5,6])

a match will never be found.


#3

What is the other thing to compare two lists, except nested for loop?


#4

nested loops is a good idea, why not use it?

of course there are always multiply ways to solve a problem, we could use list slicing:

for i in range(sequence):

then check if the current item in sequence (sequence[i]) equals the first item of item, then use list slicing to see of the rest of sequence equals item


#5

It seems to me that nested for loops take more time to process?
Maybe…?

And please, explain what slicing is, if you can?


#6

Well, you could try to see which preforms better.

list slicing has been covered in the lessons:

print ['a','b','c','d'][:2] # ['a','b']

with the right design, it can be used here


#7

Oh, I remember. I didn’t know it was called that way.
thank you very much


#8

anyway, see how far you get, if you need more help post an updated version of your code

I let you do most of the work, of course i could work out a solution, but that wouldn’t teach you as much. Writing your own solutions teaches you way more


#9

Alright, don’t close the thread until I post the right one, okay? :smiley:


#10

I only close solved topics, which is currently not the case. I still offer further assistance if needed

The topic is auto-closed 7 days after the last reply


#11

Alright, so now, it apparently works in these cases:
count([1,2,3,4,5], [1,2,3]) - printed 1
count([1,2,3,4,5], [1,2]) - printed 1
, but it doesn’t work in these cases:
count([1,2,3,4,5,6,7], [9])
count([1,2,3,4,5,1,2,3], [1,2,3]) - Instead of printing 2, it prints the else clause after while loop:

Also, I have a question regarding continue and break in nested loops.
How can I return to the 1st for/while loop if I have more then 2 or 3?
In case such as this one:

while match_count < len(item):
      for i in sequence:
        for p in item:
          if i == p:
            match_count += 1
          else:
            break

And, how can I return from else clause in while/for loop to while/for loop, in case like this:

while match_count < len(item):
    ....
else: 
    if match_count == len(item):
        occurence_count += 1
        match_count -= len(item) 
        #How to //return to //while loop?      
      else:
        ....

This is the code:

def count(sequence, item):
  occurence_count = 0
  if type(item) is int or type(item) is float or \
  type(item) is str:
    for i in sequence:
      if i == item:
        occurence_count += 1
    return occurence_count
  elif type(item) is list:
    match_count = 0
    while match_count < len(item):
      for i in sequence:
        for p in item:
          if i == p:
            match_count += 1
          else:
            break
    else: 
      if match_count == len(item):
        occurence_count += 1
        match_count -= len(item)    #This means that if the condition is met
      else:                         #match count will return to zero so the while loop can continue
        print("Sequence does not contain item") 
  print(occurence_count)
count([1, 2, 3, 4, 5, 6], [1, 2, 3])

Check this out and let me know what do you think I should change.
Thank you very much, this is very helpful, even though this is easy for you, for me it’s very hard.
:smiley:


#12

never easy. I am going to be honest, i would solve the problem differently, and find it very difficult to see how i could solve the problem your way. I get what you are attempting

I am going to need some time on this.


#13

Alright. I understand.
I just want you to know that even though there are probably functions and methods I can use in order to solve this problem, I want to try to do it my way, because that’s the real way I will learn to compare difference in complicity once I become better.

If it’s not the problem, can you just answer on two of my questions regarding continuing nested while/for loops/ :slight_smile:


#14

i think its not very interesting, given its not the way you should go.

i think a better approach to this problem would be looping over sequence, but we are going to need indexes so we have to use range:

for i in range(len(sequence)):

then if sequence[i] equals the first item of item (item[0]) we should use a zip() to loop over the part of sequence to compare it with item for which we use list slicing:

for a, b in zip(sequence[i:i+len(item)], item):

now if a != b we can break the loop. Then we add else to for loop, and increase match_count by one. else is only reached when loop finished running, and isn’t broken by break

an even better solution would to loop over sequence using range, then inside this loop, loop over item using range:

for j in range(len(item)):

this way, we could check if sequence[i] + j equals item[j], and use the same for/else with break strategy, its quit cool given we cleverly use j to also get all items of sequence list while looping over item


#15

Alright, here’s the code.
Everything seems logical. Your suggestion to remove match_count is good, so I accepted it.
Now I have this code, but it keeps popping the error:
Traceback (most recent call last):
File “D:\Python\init1.py”, line 30, in
count([1, 2, 3, 4, 5, 6, 1, 2, 3], [1, 2, 3])
File “D:\Python\init1.py”, line 20, in count
for a, b in list(sequence[i:i+len(item), item]):
TypeError: list indices must be integers or slices, not tuple

Here’s the code
Presumably, the item will have 3 elements in a list.
I just didn’t know how to add a variable which will add “if…and (aindex + n) == (bindex + n)

def count(sequence, item):
    occurrence_count = 0
    if type(item) is int or type(item) is bool or type(item) is float or type(item) is str:
        for i in sequence:
            if i == item:
                occurrence_count += 1
            else:
                continue
    elif type(item) is list:
        for i in range(0, len(sequence)-len(item)+1):
            '''
            I put this range limit because it's important not to reach out of list length.
            For instance, if I didn't deduct len(item) from len(sequence), the i iterator would go from 0-10.
            Which means that equation from following text would, at some point, be: 9:9+(3),
            and the limit of sequence is 10.
            So instead, I deducted the length of item from sequence and added 1, because i+len(item) doesn't make sense
            at the end of the loop because one step was i = 0, so I added that additional step.
            '''
            for a, b in zip(sequence[i:i+len(item), item]):
                aindex = sequence.index(a)
                bindex = item.index(b)
                if sequence[aindex] == item[bindex] and sequence[aindex+1] == item[bindex+1] \
                        and sequence[aindex+2] == item[bindex+2]:
                    occurrence_count += 1
                else:
                    continue
    print(occurrence_count)

count([1, 2, 3, 4, 5, 6, 1, 2, 3], [1, 2, 3])

Also, everything but lists works very nicely.


#16

index error might indeed be a problem, we might need to limitate range, which you did, which sounds like a very good idea :slight_smile:

Seems your are still struggling for understanding, doesn’t seem like i did a good job of explaining. At any point, feel free to add print statement to see what your code is actually doing.

look:

# my code
for a, b in zip(sequence[i:i+len(item)], item):
# your code 
for a, b in zip(sequence[i:i+len(item), item]):

they are not identical. I think its important to understand what lists zip() is producing.

actually, i am an idiot. Scratch zip, lets simplify the code for a bit:

sequence, item = [1, 2, 3, 4, 5, 6, 1, 2, 3], [1, 2, 3]
total = 0
for i in range(len(sequence)):
  if sequence[i] == item[0]:
    if sequence[i:i+len(item)] == item:
      total += 1
print total

once we determined that the current character in sequence equals the first character of item, we can simply slice the piece of sequence we want to compare with item. Much better solution to determine if there is a match

then we could apply some small optimizations:

sequence, item = [1, 2, 3, 4, 5, 6, 1, 2, 3], [1, 2, 3]
total = 0
first_item = item[0]
item_length = len(item)
for i in range(len(sequence)):
  if sequence[i] == first_item:
    if sequence[i:i+item_length] == item:
      total += 1
print total

anyway, i know this is a lot to take in.


#17

Yes, I was thinking the same about small optimization.
Let me check if the code works first.
As far as I understood, zip() creates a tuple, but I just added this little thing:

for a, b in list(zip(sequence[i:i+len(item)], item[i:len(item)])):

I just need to calculate it first.

I think I can actually manage to do it my way first.

Give me 5 minutes.


#18

https://discuss.codecademy.com/t/11-count/226076/17

Please help me understand this properly.

When I list a zip file of for instance, in this case:

            for a, b in list(zip(sequence[i:i+len(item)], item[0:len(item)])): #not i, but 0
                if sequence[a] == item[b] and sequence[a+1] == item[b+1] and sequence[a+2] == sequence[b+2]:
                            occurrence_count += 1

let’s put some numbers:

for i =0
            for a, b in list(zip(sequence[0:3], item[0:3])):
                if sequence[0] == item[0] and sequence[1] == item[1] and sequence[2] == sequence[2]
                            occurrence_count += 1

for i = 1
            for a, b in list(zip(sequence[1:4], item[0:3])):
                if sequence[1] == item[0] and sequence[2] == item[1] and sequence[3] == sequence[2]
                            occurrence_count += 1



list(zip(shit)) creates this:
[(1,1),(2,2),(3,3], right?


#19

easy enough to find out:

print zip([0,1,2,3], [0,1,2,3])

we don’t have to use for with zip(), and print always useful if you want to know something for sure


#20

I did the same thing, but the problem is that
List(zip()) doesn’t create
[1,1,2,2,3,3,4,4,…]
but
[(1,1),(2,2),(3,3)] - tuples, maybe?