0

Imagine I have a list L that has the following items:

L = [1,1,2,3]

Let's say that I want to remove each item but also count the amount of "ones", "twos" and "threes" that are on the list. So we define the following variables

ones = 0
twos = 0
threes = 0

One way I tried to solve this problem was by using a for loop and a while loop in the following way:

for item in L:
    while item in L:
        if item == 1:
            ones += 1
            L.remove(item)
        elif item == 2:
            twos += 1
            L.remove(item)
        elif item == 3:
            threes += 1
            L.remove(item)

But for whatever reason, the list L remains as

L = [2]

and the variables

ones = 2
twos = 0
threes = 1

Can someone explain why is it not removing and counting the 2 and how to fix it?

Thank you in advance.

P.S. I am aware of a way of counting items on a list (count method for example) but I would still like to know why this is happening

cenfra
  • 3
  • 2
  • Try iterating list indices instead of iterating the list itself. – ThePyGuy Sep 16 '22 at 15:29
  • "Let's say that I want to remove each item" So just do all the counting first, and then empty the list afterwards? Why make it complicated? – Karl Knechtel Sep 16 '22 at 15:42
  • You're right. I shouldn't have made it complicated. I just stumbled upon it and wanted to know why it happened. – cenfra Sep 16 '22 at 21:17

2 Answers2

1

When you start iterating over the list of numbers, you shouldn't be altering the list itself, an idea may be to copy the values to a second list and use it as support for the loop

a = [1,1,2,3]
b = a.copy()
count = {}

for i in b:
    print(i)
    if i in count:
        count[i] += 1
    else:
        count[i] = 1
    a.remove(i)
print(count)
  • 1
    Thank you for your answer. I will pay attention to not altering the list when iterating over it. – cenfra Sep 16 '22 at 21:10
0

The for loop considers the value at each index in L.

The first iteration of the for considers value at index 0.

The second iteration of the for considers value at index 1.

Since you modify the list in-situ, by the time index 1 is considered, the value there is 3.

The value 2 isn't considered because that moves to index 0, which has already been considered at that point in time.

To help illustrate this, I've used the enumerate function to expose both index and value in your for loop:

#!/usr/bin/env python

L = [1,1,2,3]

ones = 0
twos = 0
threes = 0

for index, item in enumerate(L):
    print(f"Consider value at index {index} in {L} (value: {item})")
    while item in L:
        if item == 1:
            ones += 1
            L.remove(item)
        elif item == 2:
            twos += 1
            L.remove(item)
        elif item == 3:
            threes += 1
            L.remove(item)

# Consider value at index 0 in [1, 1, 2, 3] (value: 1)
# Consider value at index 1 in [2, 3] (value: 3)

You can fix this by iterating over a copy of the list in your for.

One way of making a copy of it is to append an empty list, making a new list that's the same.

To do this, change your for to be:

for item in L+[]:

Alternatively, you can create a more concise solution by using list.count in a dict comprehension:

#!/usr/bin/env python

L = [1,1,2,3]
counts = { i:L.count(i) for i in set(L) }
print(counts)
kwiknik
  • 570
  • 3
  • 7