Control the index of a Python for loop - python

How do you control the index of a python for loop? (or can you? or should you?)
For Example:
for i in range(10):
print i
i = i + 1
Yields:
0
1
2
3
4
5
6
7
8
9
I want it to yield:
0
2
3
4
5
6
7
8
9
10
I really do apologize if I'm just completely off track with this question, and my brain is completely failing me at the moment and the solution is obvious.
Why am I asking?
This is irrelevant to the question, but relevant to the why I need the answer.
In a Python script I'm writing, I am doing something like this:
for i in persons:
for j in persons[-1(len(persons) - i - 1:]:
if j.name in i.name:
#remove j.name
else:
#remove i.name
#For every person (i), iterate trough every other person (j) after person (i)
#The reason I ask this question is because sometimes I will remove person i.
#When that happens, the index still increases and jumps over the person after i
#So I want to decrement the index so I don't skip over that person.
Maybe I am going about this completely the wrong way, maybe I should use a while loop and control my indices.

How do you control the index of a python for loop? (or can you? or should you?)
You can't / shouldn't - the loop control variable will be reassigned at the end of each iteration to the next element of whatever it is you are iterating over (so that i = i + 1 has no effect, since i will be reassigned to something different for the next iteration anyway). If you want to control the index like that, you should use a while-loop:
i = 0
while i < 10:
print i
i = i + 1
Although, Python's range function is more flexible than you might realize. For instance, to iterate in steps of 2 you can simply use something like
for i in range(0, 10, 2):
print i

Check out the docs on range here, or from the docstr:
range([start,] stop[, step]) -> list of integers
Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
These are exactly the valid indices for a list of 4 elements.
To get range from 0-10, just do:
> for i in range(0, 11):
> print i
> 0
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
> 9
> 10
By the way, it's pointless to do the i = i + 1, cause every iteration in the for loop will change i again. Whatever you set it to in the loop, will get overwritten every time the loop starts over.

Related

Augmented Assignment

I am new to the world of Python and programming in general, and today I have faced a problem with augmented assignment. I unfortunately do not understand the code, and what for i in range(multiplier) and answer *= number does. I tried understanding it but I still don't really get the logic behind it. Can somebody please explain?
number = 5
multiplier = 8
answer = 0
for i in range(multiplier):
answer *= number
print(answer)
range([start], stop[, step])
range is a function that takes a number and return a list of number from 0 ... right through to the number you gave it as an argument.
BUT THE KEY TO NOTICE IS THAT IT WILL NEVER INCLUDE THE NUMBER YOU
TOLD IT TO COUNT TO
. Example :
This is an example of giving the function range 1 argument:
>>> # One parameter
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
Here is an example of giving it two arguments where the first argument is telling the function what to start the list it returns at. The second argument is where it should end:
>>> # Two parameters
>>> for i in range(3, 6):
... print(i)
...
3
4
5
Here is an even cooler example where we use the third argument as well. This argument tells the function to count from whatever number you told it to start at, right through to whatever number you told it to stop at (just like the above to examples)... only now, the third argument tells it in what steps to count:
Like count from 2 to 12 but count in 2's:
>>> # Three parameters
>>> for i in range(2, 12, 2):
... print(i)
...
2
4
6
8
10
SO....
the for loop is just iterating through that list of numbers that is given back by the function range
so lets break that for loop in to pseudo code.
***loop***
for i in range(multiplier):
answer *= number
***Pseudo code***
Give me a list of numbers
(not giving it a start value but only a value to end the count at).
The numbers has to be from 0 to multiplier (8).
so range(multiplier) -> range(8) -> [0, 1, 2, 3, 4, 5, 6, 7]
now you have a list
now you ask the compiler to go through that list.
you say : go through that list and everytime you at a new number, give it to me in the for of a variable called i.
then when you have i, you don't use it because i was just trying to loop 8 (multiplier) times... but now take the answer and add to it this (answer * number) ... this will happen 8 times because you loop 8 times

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.

conversion from if statements to efficient for loop based solution for INSERTION SORT in Python

I have the following code that performs an insertion sort for 4 items in a list. It works, but it uses IF statements. I am interested in the various solutions that show a)conversion (based on my code and variables) to a simpler more efficient algorithm using loops where there is repetition and b) a clear explanation as to where/why what has been implemented.
The code for the insertion sort using IF statements:
def main():
list=[4,1,2,6]
print("original list:",list)
cv=list[1]
if cv<list[0]:
list[1]=list[0]
list[0]=cv
print("Compare element 1 with 0:",list)
cv=list[2]
if cv<list[1]:
list[2]=list[1]
list[1]=cv
print("Compare element 2 with 1 & shift 1 upto 2:",list)
if cv<list[0]:
list[1]=list[0]
list[0]=cv
print("Compare element 2 with 0 and shift 0 and 1 up:",list)
cv=list[3]
if cv<list[2]:
list[3]=list[2]
list[2]=cv
print("Compare element 3 with 2 & shift 2 upto 3:",list)
if cv<list[1]:
list[2]=list[1]
list[1]=cv
print("Compare element 3 with 1 and shift 1 and 2 up:",list)
if cv<list[0]:
list[1]=list[0]
list[0]=cv
print("Compare element 3 with 0 and shift 0 up:",list)
main()
How does this code above translate into a for loop/loop based solution + I'd also be interested in a recursive solution, but again derived directly from this one for teaching/learning purposes.
One could start, for example, by reocgnising that each iteration is done for lengthoflist-1 times.
So:
for i in range((len(list))-1):
cv=list[i+1]
etc
I get that there will be an outer loop and an inner loop. How are these best constructed, and again, a clear explanation as to how the solution is derived from this original if-based code, is what I'm after.
First of all, never name a list "list" as it overrides the built-in list() function. Instead, I have named it l:
l = [4, 1, 2, 6]
Then, we need to simply do a for-loop that loops over the indexes in l. We need to start at index 1 though (second element) as insertion works by shifting elements left (as you know) and so we should start at the second element and go to the last (so the length of l: len(l)).
Then we want to begin a while loop. This will continue whilst the current element at i (the index) in the list is smaller than the element to its left and i is greater than 0 (so we haven't gone off the end).
For example, in the first iteration of the for-loop, i will be 1 which has the element value of 1 in l. As 1 is greater than l[i-1] (this is 4) and i which is 1 is > 0 which it is, we enter the while.
In the while loop, all we do is switch the current element and the one to its left with the nice syntax stolen from here.
Finally, the last thing to do in the while is to decrease the index by 1 i.e. move the current position to the left so we can then to another switch if it is yet again smaller than the element to its left.
So after all that explanation, here is the code:
for i in range(1, len(l)):
while l[i] < l[i-1] and i > 0:
l[i-1], l[i] = l[i], l[i-1]
i -= 1
which modifies l to:
[1, 2, 4, 6]

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