Why isn't for loop resetting the range() function? - python

I have a code:
x = 6
for y in range(x):
print(y)
x -= 2
It gives: 0, 1, 2, 3, 4, 5
I wrongly predicted that it would give either of these 2 results:
0, 0, 0
Since x goes from 6 to 4 to 2 to 0, there will only be 3 y printed. Also, to my understanding, after each loop, it goes back to the for loop statement, thus resets the range() completely and now every y is 0. I ran the code on PythonTutor and the pointer also seemed to go back to the loop statement after each loop.
0, 1, 2
Since x goes from 6 to 4 to 2 to 0, there will only be 3 y printed. I thought it might be possible that while y takes on the value of the original range (i.e. 6), it would be limited by each new x and thus only have 3 y printed.
Possibility 1 was the most intuitive (albeit wrong) for me and I am not sure how to go about understanding why the answer is as such.

The instance of range produced by range(x) uses the value of x at the time range is called. It does not repeatedly check the value of x each time you need a new value from the range. Your code is effectively the same as
x = 6
for y in [0, 1, 2, 3, 4, 5]:
print(y)
x -= 2
Nothing you do to x has any effect on the range object being iterated.

The range() call creates a range object from x at the start of the loop. Changing x after this has no effect on the range object that is being used to iterate.
If you want to be able to change how many iterations you make in a loop, you probably want to look at using while.

Try this:
# Firstly you assign 6 to the variable x
x = 6
# 'y' will now be assigned to the numbers [0, 1, 2, 3, 4, 5, 6] because the range is 'x' which is 6.
# by printing 'x' it will execute [0, 1, 2, 3, 4, 5, 6] but since x is 'x -2' which is the same as '6 - 2' it will print out the number 6 and -2 until it gets to the range which is -6. the output will be 6 numbers [6, 4, 2, 0, -2, -4]
for y in range(x):
print(x)
x = x - 2
# i am showing you a way of making it give you your expected output [6, 4, 2, 0, -2, -4]

Related

python homework interleaving list

The problem statement is:
Design and implement an algorithm that displays the elements of a list
by interleaving an element from the beginning and an element from the
end.
For example, input:
1 2 3 4 5 6 7 8
Output :
1 8 2 7 3 6 4 5
This is what I tried, but I don't know what happen with elements 7 and 8:
lista = [1, 2, 3, 4, 5, 6, 7, 8]
for i in range(len(lista)):
lista.insert(2*i-1,lista.pop())
print("The list after shift is : " + str(lista))
# output:
# The list after shift is : [1, 7, 2, 8, 3, 6, 4, 5]
The only error in you code, is that range(len(lista)) starts from 0, not from 1. By starting from zero, in the first iteration 2*i-1 will be 2*0-1 = -1, and hence lista.insert(-1,lista.pop()), which means inserting at the very end of the list (that is what index -1 means in python).
To fix your code, you just need to start the range from 1. Actually, you are iterating too much, you can have your range just from 1 to the half of your list, like this:
lista = [1, 2, 3, 4, 5, 6, 7, 8]
for i in range(1, len(lista)//2):
lista.insert(2*i-1,lista.pop())
print("The list after shift is : " + str(lista))
# output:
# The list after shift is : [1, 8, 2, 7, 3, 6, 4, 5]
When you become more familiarized with the language, you will see that this can be accomplished much more easily.
For example, you can use the python slice syntax to achieve your goal. You slice from beginning to half , and from end to half (step of -1), then zip then together and flat.
[i for z in zip(lista[:4],lista[:-5:-1]) for i in z]
# [1, 8, 2, 7, 3, 6, 4, 5]
Another option:
import math
lista = [1, 2, 3, 4, 5, 6, 7, 8]
ans = []
for i in range(math.floor(len(lista)/2)):
ans.append(lista[i])
ans.append(lista[-i-1])
if (len(lista) % 2) != 0:
ans.append(lista(math.ceil(len(lista)/2)))
print(ans)
Technically speaking, I'd say it's two off-by-one errors (or one off-by-one error, but from -1 to +1, you'll see what I mean in the second paragraph). The first one is that you're subtracting 1 when you shouldn't. In the case when i = 0 (remember that range(n) goes from 0 to n-1), the insert position is being evaluated as 2*0-1 = (2*0)-1 = 0-1= -1 (for insert() method, that's the last position of the original list, pushing what was there forward, so it'll be the penultimate position of the NEW list).
But, when you remove the -1, the output becomes 8 1 7 2 6 3 5 4, which is close to what you want, but not quite right. What's missing is that the elements inserted should be at positions 1, 3, 5, 7, and not 0, 2, 4, 6. So, you'll actually need to add 1.
So, the shortest change to fix your code is to change lista.insert(2*i-1,lista.pop()) to lista.insert(2*i+1,lista.pop()).
Notice: if you put a print inside for, you'll realize that, after changing half the elements, the output is already right. That's because when len(lista) is 8, and you do lista.insert(x, lista.pop()) where x is bigger than 8, basically you're removing the last element (pop) and adding it at the end, so, nothing changes. Hence, you could also change range(len(lista)) to range(len(lista)//2). Test if it'll work when len(lista) is odd

Is there a way to loop through a list from a specific index that wraps back to the front onwards?

Is there a way to loop through a list from a specific index that wraps back to the front?
Let's imagine a list
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Is there a way to loop from 4 onwards, wrapping back to the front and continuing from there?
Ideally iterating through the original list as I need to modify the values.
Expected output:
4 5 6 7 8 9 0 1 2 3
Visualized example
If you want to use the iterator directly, then you can use
for x in arr[4:] + arr[:4]:
# operations on x
I used the + for concatenation assuming it is a native Python List
Otherwise if you use indices:
for i in range(len(arr)):
x = arr[(4 + i)%len(arr)]
# operations on x
There is. You can slice the list in two and iterate over them in the same loop like this:
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
idx = 4
for i in arr[idx:] + arr[:idx]:
print(i)

Python code with nested for loops is too slow

I am doing a problem from HackerRank. This problem defines a zero array of size n at the beginning and then does operations on it. So let's say that array is x = [0, 0, 0, 0, 0, 0]. So n = 6 here. Now consider the operation (they call it query in the problem) [1, 2, 5]. This means that in the array x, add 5 from index 0 to 1. So x now becomes x = [5, 5, 0, 0, 0, 0]. And there could be many such operations(queries). At the end, we just need to find the max element of the final array x. So sample input is
5 3
1 2 100
2 5 100
3 4 100
So we need to have array x of size 5 (initialized to zeros) and there are 3 queries to run on it. If we go through the queries, we find that the max element in the final array is 200. I have done code using nested for loop here. Outer for loop runs through the queries and inner for loop manipulates the array x.
For small values of array size of x, my code works good. But when n = 1000000 and number of queries, m = 100000, the nested for loops runs forever (It acts like an infinite loop). I want to know how can I make this faster.
Following is the nested for loop
# Construct a zero list of length n
worklist = list([0]*n)
# Loop through the queries
for query in queries:
# Since the problem defines the queries vector
# as one based index, we need to modify the
# indices of query
index0, index1 = query[0]-1, query[1]-1
# Now construct the new list with addition
for i in range(index0, index1+1):
worklist[i] = worklist[i] + query[2]
I think I need to modify my algorithm for doing this. Suggestions welcome.
In the Discussions page of this problem, there is a O(n) solution there,
It's the problem about overlap.
The basic thinking is, you just need to mark "add" point and "remove" point in the array, so the final stage you only need to go though the array once and keep "current sum" in current index and you can record the max one for answer.
For example
5 3
1 2 100
2 5 100
3 4 100
your array will simplify to be
0, 0, 0, 0, 0, 0
when take first input record (1 2 100):
100, 0, -100, 0, 0, 0
this means when you doing final scan sum summary, your loop will calculate in step
index 0, sum 100
index 1, sum 100
index 2, sum 0
index 3, sum 0
...
when take second input record (2 5 100):
100, 100, -100, 0, 0, -100
this means when you doing final scan sum summary, your loop will calculate in step
index 0, sum 100
index 1, sum 200
index 2, sum 100
index 3, sum 100
index 4, sum 100
index 5, sum 0
so the max is happend at index 1,
when take second input record (3 4 100):
100, 100, 0, 0, -100, -100
this means when you doing final scan sum summary, your loop will calculate in step
index 0, sum 100
index 1, sum 200
index 2, sum 200
index 3, sum 200
index 4, sum 100
index 5, sum 0
so the max is happend at index 1,
My answer addresses only the algorithmic part of your question, I'm going to simplify i/o and not to implement it as a function, to leave something on which to test your skills.
The idea is, don't store the result but the cumulative delta for each position and, afterwards, find the maximum with a cumulative summation.
Let' s see the first example reported in the statement of the problem,
10 3
1 5 3
4 8 7
6 9 1
We start with l, a list of zeros with length equal to n+1 (why n+1? because we need a little extra space to store a delta when b==n); we want to store in l just the delta's
n, m = 10, 3
l = [0]*(n+1)
We repeat the same ops for the 3 queries and report the state of our list l in a comment
a, b, k = 1, 5, 3
l[a-1] += k ; l[b] -= k
# [0, 0, 3, 0, 0, -3, 0, 0, 0, 0, 0]
a, b, k = 4, 8, 7
l[a-1] += k ; l[b] -= k
# [0, 0, 3, 7, 0, -3, 0, 0, -7, 0, 0]
a, b, k = 6, 9, 1
l[a-1] += k ; l[b] -= k
# [0, 0, 3, 7, 1, -3, 0, 0, -7, -1, 0]
current_max = 0
current_sum = 0
debug = 1
for num in l[:-1]:
current_sum += num
if debug: print(current_sum)
current_max = max(current_max, current_sum)
print(current_max)
Executing the above code gives me
3
3
3
10
10
8
8
8
1
0
10
The first ten numbers are the elements of the summed list, to be compared with the problem statement, and the last number is the required maximum value

How to Transfer a number in an array from one position to another

I would like to know how to transfer a number.
For example: [1,0,2,3,4]
Remove the one and transfer the one to two's position
Result: [0,0,1,3,4]
If your manipulations are purely index-based, you can do this:
lst = [1,0,2,3,4]
lst[2] = lst[0]
lst[0] = 0
# [0, 0, 1, 3, 4]
Alternatively, if you need to work out the index of 2:
lst[lst.index(2)] = lst[0]
lst[0] = 0
Since you have not described your question with clear instructions, There is case when there will be more than one 2 or 1 in vector then what you want to do ?
My solution is only for that condition when there is single 1 and 2 in vector because when you use .index method it always returns first value index no matter there are other values too.
Since in your dataset there is always 1 times 1 and 2 in all vector so here is the solution for that
data=[[1, 2, 3, 4, 0], [1, 3, 2, 4, 0], [2, 1, 3, 4, 0] ]
def replace_ (vector_ , replace_value, replace_with):
memory=vector_.index(replace_with)
vector_[vector_.index(replace_value)]=vector_[vector_.index(replace_with)]
vector_[memory]=0
return vector_
for i in data:
print(replace_(i,1,2))
If there are more than one 1 or 2 in vector like [1,0,1,1,2,2] then describe your logic and edit your question for that.

I need to know why this is the output for these python condition

numbers=[i**3 for i in range (10) if i**3%3==1]
print(numbers)
#gets 1,64,343
Why is 1, 64, 343 the answer?
This is equivalent to the code:
for i in range(10):
if (i*i*i) % 3 == 1:
numbers.append(i*i*i)
print (numbers)
You are checking if the remainder obtained when the cube of a number from 1 to 10 is divided by 3 is equal to 1. If it is, you are adding it to a list and printing it.
The meaning of **
ex: 2**3= 2*2*2 #this means 2 to the power 3 = 8
The meaning of %
ex: 5%2= 1 #the sign means module, that means the remaining value after divide 5 by 2, it is one.
in your way, the correct path to write the for each is
for i in range(0,10):
value = i**3
if(value%3 == 1):
print("the value is {0}".format(value))
so the result is :
the value is 1
the value is 64
the value is 343
bit explanation inside the for loop
first get the i = 0, at this point value = 0*0*0 = 0, then value%3=0
then get the i=1, at this point value = 1*1*1 = 1 ,the 'value%3' means 1%3 = 1, so the answer i 1
.... like this see about other conditions also. hope this will help to you.
first i is in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
then if (i*i*i) rem 3 is equal to 1
it selects (i*i*i)
and for [1,4,7]: (1*1*1)%3==1, (4*4*4)%3==1 and (7*7*7)%3==1:
1*1*1=1 and 1/3=0 :remainder=1
4*4*4=64 and 64/3=21 :remainder=1
7*7*7=343 and 343/3=114 :remainder=1
so the output is:
[1*1*1, 4*4*4, 7*7*7] which is [1, 64, 343]
your code:
numbers=[i**3 for i in range (10) if i**3%3==1]
print(numbers)
and this code:
numbers=[]
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
if (i*i*i) % 3 == 1:
numbers.append(i*i*i)
print(numbers)
output this:
[1, 64, 343]

Categories