Python, For loop counter do not update? - python

I am writing a simple program which gives the list of all prime no. less than a given no. N.
I am facing a problem that my for loop counter check in the function primes_gen else clause do not updates. Though, when i use the same logic without a function, as mention in the second code snippet, everything works correct.
Logic applied:-
when n passed to function is <= 2, blank list is returned
when n is > 2, range(3,n,2) identifies all the odd number. This is step 1 marked in first code snippet.
second for loop, marked with step 2, checks if no. is divisible to the all no.'s less than i. If yes then check counter is incremented by +1 and this loop is ended with 'continue'
if check remains zero till the end of the for loop then i is appended to the list and the finally after completion of the loop list is returned.
Problem:-
-The list i got as a result was [2] which is wrong ans. so I wrote step 3, as marked in 1st snippet, and i found that my check counter do not updates after the 'continue', as shown in the output. when same logic is applied without a function as written in second code snippet everything works correct.
I am not able to get what is going wrong here, why does check do not updates after continue?
contents =['10']
def prime_gen(n):
num_list=[2]
if n <=2:
return []
else:
for i in range(3,n,2): #step 1
check=0
for u in (2,i): #step 2
if i%u == 0:
check += 1
continue
print (check,i) #step 3
if check == 0:
num_list.append(i)
return num_list
if __name__== '__main__':
for j in range(len(contents)):
print (int(contents[j]))
num_list = prime_gen(int(contents[j]))
print (str(num_list).replace('[','').replace(']',''))
Output
10
1 3
1 5
1 7
1 9
2
Expected ans is (when step 3 above is commented)
10
2, 3, 5, 7
Second code without function
contents = ['10'] #to-check
for i in range(len(contents)):
target = int(contents[i])
num_list= [2]
for j in range(3,target,2):
check = 0
for u in range(2,j):
if j%u == 0:
check +=1
continue
if check == 0:
num_list.append(j)
#print (num_list)
print (str(num_list).replace('[','').replace(']',''))
output
2, 3, 5, 7

Your problem took a second to find, but is very simple to solve. The issue is at your "Step 2". You have the line
for u in (2,i): #step 2
That iterates u through all the variables in the tuple you provide, namely 2 and i. Of course, i%i will be 0, so check will always be true. What you want instead is this:
for u in range(2,i): #step 2
This will iterate u through all the variables between 2 and i, as you intend.
See these two examples:
>>> i = 7
>>> for u in (2,i): print u,
2 7
>>> for u in range(2,i): print u,
2 3 4 5 6
Basically, you just forgot to use range in your for loop, and that's going to give you wildly different results than what you actually want.

Related

Writing a function to perform Collatz Conjecture

I am asked to complete the rest of this code:
def collatz_step(n):
if n % 2 == 0:
return n // 2
and write a while loop that will set n to the next value given by collatz_step until it reaches 1, printing the value of n at each step.
which I completed as follows, which should give me 10, 5, 16, 8, 4, 2, 1
def collatz_step(n):
if n % 2 == 0:
return n // 2
else:
return 3*n + 1
while n != 1:
n = collatz_step(n)
print(n)
collatz_step(3)
but I get an error saying that 'n' is not defined? this part specifically,
while n != 1:
how do I solve this to get the correct results?
I see two things wrong:
You never define n before trying to use it.
At the end you call the function again but do nothing with the result.
It sounds like you just want to define n and then call the function in your loop, not again at the end. So something like:
# no changes to the function definition
n = 3
while n != 1:
n = collatz_step(n)
print(n)
Just think about it semantically... You want to start with a value of 3 and then repeat the operation of updating that value until it equals 1. So first you define a variable with the value you want, then you write a loop in which you update that value until the loop condition is met.

Why doesn't this sorting method work in Python?

I've got this code to sort a list without using the sorted function in python. The output is the opposite to what is expected (largest to smallest rather than smallest to largest)
Changing the < to a > seems to help but im not sure why this is
lista=[2,1,5,1,3,6]
for i in range(len(lista)):
for l in range(len(lista)):
if i==l:
continue
if lista[l]<lista[i]:
temp=lista[i]
lista[i]=lista[l]
lista[l]=temp
print(lista)
expected output list that is smalled to largest, but getting the opposite unless I change the < sign to a > sign, but I'm not sure why this is?
Try to write on paper every iteration of your algorithm:
i = 0: 2 1 5 1 3 6
i = 1: 1 2 5 1 3 6
i = 2: 2 1 5 1 3 6
your issue is that the inner loop for l in range(len(lista)): start every time from 0, but instead you have to start from position i. When you finish the inner loop you increment i of 1 and everything that is before i is already sorted. If the inner loop restart from the begin like in this case you will have that 1 is less than 2 (on i = 1) you swap it again.
lista=[2,1,5,1,3,6]
for i in range(len(lista)):
for l in range(i, len(lista)):
if i==l:
continue
if lista[l]<lista[i]:
temp=lista[i]
lista[i]=lista[l]
lista[l]=temp
I recommend you to read about insertion sort and selection sort to learn better this algorithm.
The problem is that the second loop goes through the entire list again. What you'd want to do is to look at the remaining elements instead:
lista = [2, 1, 5, 1, 3, 6]
for i in range(len(lista)):
# change range to start at i
for l in range(i, len(lista)):
if i == l:
continue
if lista[l] < lista[i]:
temp = lista[i]
lista[i] = lista[l]
lista[l] = temp
edit: To be more specific, think about what happens on the last iteration of the outer loop. lista[i] will be the last spot on the list, and you're swapping each time lista[l] is smaller, so in the end you have the smallest number as the last one.

How to change the elements in an array in the process using Python 3?

I am making a program where I can fix the sequence of a list, the sequence is to be followed with a difference of 2. In this program if the difference is less than 2 I need to replace/change a certain number. Well, I have done most of the part but the problem is I can't replace it properly, and since I can't change the number in the process my output also comes out wrong.
list_1 = [1,2,5]
for i in range(1, len(list_1)):
htl = list_1[i]-list_1[i-1]
if not htl == 2:
list_1[i-1] += 2
print(list_1[i-1])
The output is:
3
4
But it's wrong, the correct ouput is:
3
Because I only need to change the number 2 to 3 to make it a correct sequence.
What I am doing in my code is that, I am subtracting backwards to spot the differences. If there is a difference, I am trying to add 2 to number it is being subtracted from, and then change the number that is being subtracted. But in my program I am having problem in replacing. For example(the subtraction starts from index 1 - index 0, index 2 - index 1 and it goes on): 2-1 = 1 so it's not clearly following the sequence, and I am trying to replace the 2 in 'list_1' with 3(by adding 2 to the number that index 1 is being subtracted from). I can't replace the number and since I can't replace that,the next output comes that shouldn't be there because only one change is needed.
My way may be really tangled up, but it was the best I could think of, if there is a faster way I would really appreciate the help. But otherwise I did like to fix my Code, where the general idea is to follow the sequence of 2.
The attribution is wrong:
list_1 = [1,2,5]
for i in range(1, len(list_1)):
htl = list_1[i]-list_1[i-1]
if htl != 2:
list_1[i] = list_1[i-1] + 2
print (list_1)
Output:
[1, 3, 5]
But in the end, what you want is simply a sequence starting at an initial point and with a step of 2 and with a certain number of points
start = 1
points = 3
stop = points * 2 + start
list_1 = list(range(start, stop, 2))
Output:
Out[11]: [1, 3, 5]
Less than 2?
I also think you were changing the -1 list value rather than the current index.
This should work?
list_1 = [1,2,5,6,7,8,15]
for i in range(1, len(list_1)):
htl = list_1[i]-list_1[i-1]
if htl < 2:
list_1[i] =list_1[i-1]+2
print(list_1[i-1])
print(list_1)
If i understand your explanation, you wish to convert
list_1 = [1,2,5] to list_1 = [1,3,5]
The line which is not giving the desired result is:
list_1[i-1] += 2
The first time the for loop iterates, it generates list_1 = [3,2,5].
The second time it iterates, it generates list_1 = [3,4,5].
Change the line:
list_1[i-1] += 2
to:
list_1[i] = list_1[i-1] + 2
Update:
You said if the difference is less than 2, you wish to make the change.
Consider changing the if not htl ==2: condition to if htl < 2. This will then catch the situation where you have two consecutive elements which are equal. It also reads better.
Update 2:
In order to catch an error where your list has only zero or one elements, I recommend you place a condition before the loop. if len(list_1) > 1: would be a good place to start, otherwise the indexing will raise an IndexError.
I'm not sure to have totally understand what you want to do but first, to fixe you output probleme change :
list_1[i-1] += 2
by
list_1[i-1] += 2
and put your print outside of the for like that :
for i in range(1, len(list_1)):
htl = list_1[i]-list_1[i-1]
if not htl == 2:
list_1[i-1] += 1
print(list_1[i-1])
print(list_1[i-1])
Hope that can help you.

how to increment the iterator from inside for loop in python 3?

for i in range (0, 81):
output = send command
while True:
last_byte = last_byte - offset
if last_byte > offset:
output = send command
i+
else:
output = send command
i+
break
I want to increase the iterator every time the send command is executed. Right now it only increases by one when the for loop is executed. Please advise
for i in range(0,10):
print(i)
i +=2
print("increased i", i)
I ran this code and it produced out from 0 to 9. I was expecting it would increase the iterator by 2.
Save a copy of the iterator as a named object. Then you can skip ahead if you want to.
>>> myiter = iter(range(0, 10))
>>> for i in myiter:
print(i)
next(myiter, None)
...
0
2
4
6
8
You can't do this inside a for loop, because every time the loop is restarted it reassigns the variable i regardless of your changes on the variable.
To be able to manipulate your loop counting variable, a good way is to use a while loop and increase the throwaway variable manually.
>>> i = 0
>>> while i < 10 :
... print(i)
... i += 2
... print("increased i", i)
...
0
('increased i', 2)
2
('increased i', 4)
4
...
Additionally, if you want to increase the variable on a period rather than based on some particular condition, you can use a proper slicers to slice the iterable on which you're looping over. For instance, if you have an iterator you can use itertools.islice() if you have a list you can simply use steps while indexing (my_list[start:end:step]).
range() has an optional third parameter to specify the step. Use that to increment the counter by two. For example:
for i in range(0, 10, 2):
print(i)
print("increased i", i)
The reason that you cannot increment i like a normal variable is because when the for-loop starts to execute, a list (or a range object in Python 3+) is created, and i merely represents each value in that object incrementally.
#ilaunchpad Sorry I know it's too late to post this but here is what you were looking for
i=0
for J in range(0,10):
print(i)
i = i + 2
print("increased i", i)
You should not use the same variable throughout in the For statement.
Output
vaibhav#vaibhav-Lenovo-G570:~$ python3 /home/vaibhav/Desktop/Python/pattern_test.py
0
2
4
6
8
10
12
14
16
18
increased i 20
How about this?
for i in range(10):
if i == 3:
i += 1
continue
print(i)
Just adding the continue makes the counter go up - the print result is:
0
1
2
4
5
6
7
8
9
Note that without the continue, the 4 will be printed twice.
I think this answers the question.
I wrote something like this.
while True:
if l < 5:
print "l in while", l
l += 1
else:
break
Now I am having a full control but the backdrop is that I have to check all the conditions.
As there are no answers that allow to use the result of the next iterator, here is my proposed solution, that works with many lists and iterables by using either the enumerate() function or just the iter() function:
x = [1, True, 3, '4', 5.05, 6, 7, 8, 9, 10]
x_enum = enumerate(x)
for idx, elem in x_enum:
if idx == 1: # Example condition to catch the element, where we want to iterate manually
print('$: {}'.format(elem))
idx, elem = next(x_enum)
print('$: {}'.format(elem))
else:
print(elem)
will print:
1
$: True # As you can see, we are in the if block
$: 3 # This is the second print statement, which uses the result of next()
4
5.05
6
7
8
9
10
This is also possible with a simple iterator:
x_iter = iter(x)
for elem in x_iter:
if elem == '4': # Example condition to catch the element, where we want to iterate manually
print('$: {}'.format(elem))
elem = next(x_iter)
print('$: {}'.format(elem))
else:
print(elem)

How to change for-loop iterator variable in the loop in Python?

I want to know if is it possible to change the value of the iterator in its for-loop?
For example I want to write a program to calculate prime factor of a number in the below way :
def primeFactors(number):
for i in range(2,number+1):
if (number%i==0)
print(i,end=',')
number=number/i
i=i-1 #to check that factor again!
My question : Is it possible to change the last two line in a way that when I change i and number in the if block, their value change in the for loop!
Update: Defining the iterator as a global variable, could help me? Why?
Short answer (like Daniel Roseman's): No
Long answer: No, but this does what you want:
def redo_range(start, end):
while start < end:
start += 1
redo = (yield start)
if redo:
start -= 2
redone_5 = False
r = redo_range(2, 10)
for i in r:
print(i)
if i == 5 and not redone_5:
r.send(True)
redone_5 = True
Output:
3
4
5
5
6
7
8
9
10
As you can see, 5 gets repeated. It used a generator function which allows the last value of the index variable to be repeated. There are simpler methods (while loops, list of values to check, etc.) but this one matches you code the closest.
No.
Python's for loop is like other languages' foreach loops. Your i variable is not a counter, it is the value of each element in a list, in this case the list of numbers between 2 and number+1. Even if you changed the value, that would not change what was the next element in that list.
The standard way of dealing with this is to completely exhaust the divisions by i in the body of the for loop itself:
def primeFactors(number):
for i in range(2,number+1):
while number % i == 0:
print(i, end=',')
number /= i
It's slightly more efficient to do the division and remainder in one step:
def primeFactors(number):
for i in range(2, number+1):
while True:
q, r = divmod(number, i)
if r != 0:
break
print(i, end=',')
number = q
The only way to change the next value yielded is to somehow tell the iterable what the next value to yield should be. With a lot of standard iterables, this isn't possible. however, you can do it with a specially coded generator:
def crazy_iter(iterable):
iterable = iter(iterable)
for item in iterable:
sent = yield item
if sent is not None:
yield None # Return value of `iterable.send(...)`
yield sent
num = 10
iterable = crazy_iter(range(2, 11))
for i in iterable:
if not num%i:
print i
num /= i
if i > 2:
iterable.send(i-1)
I would definitely not argue that this is easier to read than the equivalent while loop, but it does demonstrate sending stuff to a generator which may gain your team points at your next local programming trivia night.
It is not possible the way you are doing it. The for loop variable can be changed inside each loop iteration, like this:
for a in range (1, 6):
print a
a = a + 1
print a
print
The resulting output is:
1
2
2
3
3
4
4
5
5
6
It does get modified inside each for loop iteration.
The reason for the behavior displayed by Python's for loop is that, at the beginning of each iteration, the for loop variable is assinged the next unused value from the specified iterator. Therefore, whatever changes you make to the for loop variable get effectively destroyed at the beginning of each iteration.
To achieve what I think you may be needing, you should probably use a while loop, providing your own counter variable, your own increment code and any special case modifications for it you may need inside your loop. Example:
a = 1
while a <= 5:
print a
if a == 3:
a = a + 1
a = a + 1
print a
print
The resulting output is:
1
2
2
3
3
5
5
6
Yes, we can only if we dont change the reference of the object that we are using. If we can edit the number by accessing the reference of number variable, then what you asked is possible.
A simple example:
a=[1,2,3]
a=a+[4]==>here, a new object is created which plots to different address.
a+=[4]==>here , the same object is getting updated which give us the desired result.
number=10
list1=list(range(2,number+1))
# list1
for i in list1:
print(list1,i)
if (number%i==0):
print(i,end=',')
number=number//i #we can simply replace it with number//=i to edit the number without changing the reference or without creating a new object.
try:
[list1.pop() for i in range(10,0,-1) if(i>number)]
#here pop() method is working on the same object which list created by number refers. so, we can able to change the iterable in the forloop.
except:
continue
i=i-1 #to check that factor again!

Categories