Need help understanding Python Nested For Loop - python

I'm having trouble understanding the 2nd for loop in the code below:
di = [4,5,6]
for i in range(len(di)):
total = di[i]
for j in range(i+1,len(di)):
total += di[j]
curr_di = total / ((j-i+1)**2)
I can't visualize what happens in for j in range(i+1,len(di)):, in particular the i+1 portion confuses me. how does the i in the first loop affect the 2nd loop, if any?

The first loop is simply looping over the indices available in list di. For each entry in that loop, the second loop then examines the remaining portions of di.
So, on the first iteration, we're examining the value 4. The second loop will then walk the list starting at that position, and running to the end (it will examine items 5 and 6).
On the second iteration, we'll examine entry 5, then walk the remainder of the list in the second loop (in this case 6). Make sense?
As a commenter pointed out, print statements are your friend. Here's an example with some print statements to show how i and j change:
di = [4,5,6,7]
for i in range(len(di)):
print(f"i: {i}")
total = di[i]
for j in range(i+1, len(di)):
print(f" - j: {j}")
total += di[j]
curr_di = total / ((j-i+1)**2)
Output:
i: 0
- j: 1
- j: 2
- j: 3
i: 1
- j: 2
- j: 3
i: 2
- j: 3
i: 3

This is a typical "combinations of 2" loop. Each item in the list (index i) is processed with every subsequent item (index j).
It looks like sequence processing to compute a sum of partial sums:
total = ∑(i=1..n) ( ∑(j=i..n) a[j] )

Related

Why does my python program ignore/skip some cases

I'm trying to write a code which does the following:
In the first line, it inputs two space-separated integers, the first presents the length of the list which will be input later, and the second presents an int, called k, which will be needed later on.
In the second line, the list I talked about will be input
The expected output is what meets the following criteria:
number of pairs of ( i , j ), where i<j and ar[ i ]+ar[ j ] is divisible by k.
Problem: I don't know why my code ignores some pairs. I have tried it with many test cases, and it fails 90% of them, by outputting less pairs than expected. I know I am pretty close to the right result, I just don't know what I'm not doing right.
For more precise information about what I want my code to do, kindly check this link (No signup or login needed): https://www.hackerrank.com/challenges/divisible-sum-pairs/problem
Here is my code:
#https://www.hackerrank.com/challenges/divisible-sum-pairs/problem
samples_and_k = [int(x) for x in input().split()]
num_list = [int(y) for y in input().split()]
num_list.sort()
counter =0
for i in range(0, samples_and_k[0]-1):
for j in range(i+1, samples_and_k[0]-1):
if (num_list[i]+num_list[i+1]) % samples_and_k[1] == 0:
counter += 1
print(counter)
Here's an example:
Input:
6 3
1 3 2 6 1 2
Expected output:
5
The output of MY code:
3
The problem is that you subtract 1 when using range():
for i in range(0, samples_and_k[0]-1):
for j in range(i+1, samples_and_k[0]-1):
if (num_list[i]+num_list[i+1]) % samples_and_k[1] == 0:
counter += 1
It should be:
for i in range(0, samples_and_k[0]):
for j in range(i+1, samples_and_k[0]):
if (num_list[i]+num_list[i+1]) % samples_and_k[1] == 0:
counter += 1
It's a common misunderstanding when using range(), as range() is implemented somewhat unintuitively (in my opinion). The last number is not included in the range, so list(range(0, 6)) is equal to [0, 1, 2, 3, 4, 5].

While loop not giving desired outcome

New to python here, so not sure if I'm posting in the right place but I was wondering why the following loop does not give an answer. I am trying to add all of the numbers previous to i, (1 + 2 + 3 + ... + i), but the loop I came up with does not complete.
j = 0
i = 17
while i > 0:
j = j + i
i - 1
print(j)
I expect j = 153, but the loop doesn't put out anything.
The issue is with i--you're not properly reducing it by 1, so this is an infinite loop. Try this:
j = 0
i = 17
while i > 0:
j = j + i
i -= 1
print(j)
Notice that your line in the while statement,
i-1, does not assign (= operator) a value to i. i stays 17 forever and ever, and so you see no output because the program gets stuck in your while loop. Try to fix your i assignment, like so:
j = 0
i = 17
while i > 0:
j = j + i
i = i - 1 # <= i = i - 1
print(j)
One way to debug your loop in the future is to put a print statement in the middle, like in the code below. The extra print statements slow your program down a bit, but you'll be able to easily see that your loop is going way more than you want!
j = 0
i = 17
while i > 0:
j = j + i
i = i - 1
print(j)
print(i) # so that we can see that i is going down :P
print(j)
Good luck :)
As noted above, you're not re-assigning to your i within the loop. But I'd also note that it's generally a bad idea to modify an iterator within the iteration loop. You can achieve the expected results in a more pythonic way using a range expression, and wrap it in a function also :)
def foo(max_num):
j = 0
for i in range(max_num+1):
j += i
return j
But even better, without the loop:
def foo(max_num):
return sum(range(max_num+1))
There are a couple of ways to do what you want to do. The way I recommend you do it is as shown below.
total = 0
i = 18
for j in range(i):
total += j
print(total)
The range(i) takes a maximum number i, and allows you to iterate through every number starting from 0 to i-1 (e.g. i = 5 will add numbers 0,1,2,3,4), therefore always make i one more than you need it to be if you want to be if you want to include the max number.
As already stated i - 1 wasn't assigned back to i
Following is a pythonic way of implementing the loop with a list comprehension
Code:
j = 0
i = 17
j = sum([j + x for x in range(i, 0, -1)])
print(j)
>>> 153
As a Function:
def sum_of_steps(start: int, stop: int, step: int) -> int:
return sum([x for x in range(start, stop, step)])
j = sum_of_steps(17, 0, -1)
print(j)
>>> 153
The function, sum_of_steps uses type hints or function annotations.
Python Basics: List Comprehensions

Bubble sorting numbers prob

I am trying an algorithm for a bubble sort and there is a part I don't understand
nums = [1,4,3,2,10,6,8,5]
for i in range (len(nums)-1,0,-1):
for j in range(i):
if nums[j] > nums[j+1]:
temp = nums[j]
nums[j] = nums[j+1]
nums[j+1] = temp
print(nums)
what does the numbers (-1,0,-1) mean in this part of the code (it dosent sort properly without it) v v v
for i in range (len(nums)-1,0,-1):
Syntax for range in python is -
range(start, end, step)
In your case, the looping is essentially starting from the last element(Index n-1) & moving towards the first element(Index 0) one step at a time.
Okey:
first one is starting point, second tells python where to stop, last one is step.
len(nums) - it gives you (durms..) length of this list, in our case it's 8,
len(nums)-1 - it's 8-1, we are doing this because when going through list python will start on number 0 and end at number 7(still 8 elements, but last one has index 7 not 8),
We will stop at 0, with step -1. So iteration will look like:
num[len(nums)-1] = num[7]
num[len(nums)-1-1] = num[6]
num[len(nums)-1-1-1] = num[5]
.....
num[len(nums)-1-1-1-1-1-1-1] = num[0]

Program terminated due to time out

PROBLEM :
You are given a list of size N, initialized with zeroes. You have to perform M operations on the list and output the maximum of final values of all the elements in the list. For every operation, you are given three integers a,b and k and you have to add value to all the elements ranging from index a to b(both inclusive).
Input Format
First line will contain two integers N and M separated by a single space.
Next lines will contain three integers a,b and k separated by a single space.
Numbers in list are numbered from 1 to N.
Here is the code which I have written:
n,m=map(int,input().split())
arr=[]
for i in range(n+1):
arr.append(0)
for j in range(m):
a,b,k=map(int,input().split())
for i in range(a,b+1):
arr[i]+=k;
print(max(arr))
When I try to submit my solution I get a "TERMINATED DUE TO TIMOUT" message.Could you please suggest a strategy to avoid these kind of errors and also a solution to the problem.
Thanks in advance!
Don't loop over the list range; instead, use map again to increment the indicated values. Something like
for j in range(m):
a,b,k=map(int,input().split())
arr[a:b+1] = map(lambda <increment-by-k>, arr[a:b+1])
This should let your resident optimization swoop in and save some time.
You probably need an algorithm that has better complexity than O(M*N).
You can put interval delimiters in a list:
n,m=map(int,input().split())
intervals = []
arr = [0 for i in range(n)]
for j in range(m):
a,b,k=map(int,input().split())
intervals += [(str(a), "begin", k)]
intervals += [(str(b), "end", k)]
intervals = sorted(intervals, key=lambda x: x[0]+x[1])
k, i = 0, 0
for op in intervals:
ind = int(op[0])
if op[1] == "begin":
while ind > i:
arr[i] += k
i += 1
k += op[2]
else:
while i <= ind:
arr[i] += k
i+= 1
k -= op[2]
print(arr)
If the sorting algorithm is O(MlogM), this is O(MlogM + N)

Nested while loop not looping properly in python

I'm new, and I have a question about my python code. It doesn't execute like I think it should.
The part that's messing up is in the nested while:
import math
mu=4*math.pi*10**(-7) ##mu naught
I=
float(input('Enter a value for the current measured in Amperes: '))
R=abs(float(input('Enter a value for the radius
of the circle measured in meters: '))) ##radius
step=R/200 ##Step size for integration
B=[] ##array for B(r)
J=[]
Plot=[B,J]
k = 1 ##step counter for Circumfrence
j = 1 ##step counter for Radius
b_temp = 0 ##place holder to sum b(step*k)
D_Vector = [R*math.cos(k*math.pi/100),R*math.sin(k*math.pi/100)]
R_Vector = [R-j*step,0]
while(j*step<=R):
while(k*step<=2*math.pi*R):
r=(math.sqrt((R_Vector[0]-D_Vector[0])**2 +
(R_Vector[1]-D_Vector[1])**2))
b_temp = b_temp + (mu/(4*math.pi))*I*step*step/(r**2)
k=k+1
D_Vector = [R*math.cos(k*math.pi/100),R*math.sin(k*math.pi/100)]
R_Vector = [R-j*step,0]
print(round(r,3), j)
B.append(round(b_temp,8))
print('New j value!')
b_temp=0
J.append(round(step*j,3))
j=j+1
It's supposed to step down the radius (the first while loop) and then loop around the circle, summing the magnetic field contribution for each chunk of wire. For some reason, it's not looping through the inner loop each iteration of the outer loop like it should be, and I'm honestly not sure why. The new j value line is to let me see if it's looping properly, and this is my output:
...
13.657 1
13.884 1
14.107 1
14.327 1
14.543 1
14.756 1
14.965 1
15.17 1
15.372 1
New j value!
New j value!
New j value!
New j value!
New j value!
New j value!
New j value!
New j value!
...
The 1 at the end of each float (radius value) is the j value, which stays at 1 for each circle around the loop...
You are increasing k but never resetting it to 1. so k * step becomes bigger and bigger until the condition of the inner loop becomes false. At which point is clear that it's not getting executed anymore.
Note that you should avoid while loops when the you are simply iterating over an integer range. Just use for j in range(a, b). This avoid exactly the kind of bug you have in your code.
If I'm not mistaken you can replace the loops with:
area = 2*math.pi*R
for j in range(1, R//step + 1):
# j*step <= R holds
for k in range(1, area // step + 1):
# k * step <= area holds here
where a // b is quotient of a and b.

Categories