Adam Michalski
Adam Michalski

Reputation: 15

Why is for loop iterating over (seemingly) empty list?

I'm a beginner programmer, I decided to write a simple program getting prime factors out of a number and then printing them, but I'm having trouble in printing the final result. Here's the code:

n = int(raw_input("Number?: "))
m = n
k = 2
czynniki = []       

while(m != 1):
    if m%k == 0:
        czynniki.append(k)
        print m, "\t", '|', k
        m = m/k
    else:
        k+=1
print m

print n, ' = ',
for czynnik in czynniki:
    if czynniki.count(czynnik)>1:
        print czynnik, '^', czynniki.count(czynnik), ' *',
        czynniki = filter(lambda x: x!=czynnik, czynniki)
    else:
        print czynnik, ' *',

Everything is okay until the very end. For example I'd like it to print "1025 = 5^2 * 41" when 1025 is inputed, but instead it will print "1025 = 5^2 * 5 * 41", as if filter function had no impact at all. Where's the bug?

Upvotes: 0

Views: 150

Answers (3)

felerian
felerian

Reputation: 653

The problem is that you are modifying the list czynniki while iterating over it. Try this instead:

print n, ' = ',
for czynnik in sorted(set(czynniki)):
    if czynniki.count(czynnik)>1:
        print czynnik, '^', czynniki.count(czynnik), '*',
    else:
        print czynnik, '*',

Here you iterate over a separate list of only unique items of your list czynniki. This is achieved by casting the list to a set (an unsorted list of unique items) and then back to a sorted list.

If you want to get rid of that surplus * at the end, you could try this:

result_list = []
for czynnik in sorted(set(czynniki)):
    if czynniki.count(czynnik)>1:
        result_list.append(str(czynnik) + '^' + str(czynniki.count(czynnik)))
    else:
        result_list.append(str(czynnik))
print n, '=', ' * '.join(result_list)

Upvotes: 2

Joachim Isaksson
Joachim Isaksson

Reputation: 180867

You're starting the for loop over the list that is stored in czynniki, that you're later changing what czynniki references (a totally new list) does not change which list the for loops over. It's not safe to change the actual list a loop is running over either, so you can't really do it like this either way.

You may want to rewrite the loop something like this, just skip the duplicate values instead and not try to change the loop while running;

var lastvalue = -1;
for czynnik in czynniki:
    if lastvalue == czynnik:
        continue
    if czynniki.count(czynnik)>1:
        print czynnik, '^', czynniki.count(czynnik), ' *',
        lastvalue = czynnik
    else:
        print czynnik, ' *',

Upvotes: 1

MichaelT
MichaelT

Reputation: 7934

You should use continue keyword if you want to skip some item in a loop instead of filtering collection you trying to go over.

Upvotes: 0

Related Questions