Euler method for two dimension system - python

I am absolutely a beginner in programming. and trying to write an algorithm of the Euler method for interaction two systems. When I run the code I got this Error message. I will appreciate it if you help me. Thank you.
IndexError: list assignment index out of range
def NmDef(U1, V1, U2, V2):
Nm = math.sqrt((U1-V1)**2+(U2-V2)**2) #sqrt
return Nm
NmDef_value = []
for i in range(n):
i +=1
L = NmDef(U[i], V[i], U[i-1], V[i-1])
print(i, L)
NmDef_value.append(L)

I can see that you have many errors in the for loops.
First in this for loop you have:
NmDef_value = []
for i in range(n):
i +=1
L = NmDef(U[i], V[i], U[i-1], V[i-1])
print(i, L)
NmDef_value.append(L)
In this code the foor loop is incrementing the i value by 1 on each step. In you case it is incrementing it by 1 and you are also incrementing it by 1 so on each iteration you are incrementing i by 2. When you will arrive at the last element of the list you will have i = n and you can only take the element of a list with the value n-1 or else you will get index out of range. You can fix it like that:
NmDef_value = []
for i in range(1,n):
L = NmDef(U[i], V[i], U[i-1], V[i-1])
print(i, L)
NmDef_value.append(L)
For the second for loop:
for i in range (n):
U[i]=U[i-1]+dt*(Fa[i]+Fr[i])
V[i]=V[i-1]-dt*(Fa[i]+Fr[i])
for i in range (n):
print(U[i], V[i])
In this one for i = 0 you are trying to access U[i-1] so it is U[-1] and it will be out of range too. You can add a can start the for loop with 1 like that: for i in range(1,n)

Related

Modify the elements of a list inside a for loop (Python equivalent of Matlab code with a nested loop)

I have the following Matlab code (adopted from Programming and Numerical Methods in MATLAB by Otto&Denier, page 75)
clear all
p = input('Enter the power you require: ');
points = p+2;
n = 1:points;
for N = n
sums(N) = 0;
for j = 1:N
sums(N) = sums(N)+j^p;
end
end
The output for 3 as the given value of p is the following list
>> sums
sums =
1 9 36 100 225
I have written the following Python code (maybe not the most 'Pythonic way') trying to follow as much as possible Matlab instructions.
p = int(input('Enter the power you require: '))
points = p+2
n = range(points)
for N in range(1, len(n)+1):
sums = [0]*N
for index, item in list(enumerate(sums)):
sums[index] = item+index**p
Nevertheless the output is not same list. I have tried to replace the inner loop with
for j in range(1,N+1):
sums[N] = sums[N]+j**p
but this results to an index error message. Thanks in advance for any suggestions.
This might be due to the index difference. In Python, it starts from 0 while it's 1 in Matlab. Also, sums = [0]*N initialize a list of a length N, this has to be moved outside of the loop.
points = p+2
sums = [0]*points
for N in range(0, points):
for index in range(0, N+1):
sums[N] = sums[N] + (index+1)**p
sums(N) = 0; does not create an array of all zeros, it sets element N of the existing array to 0, and creates additional elements in the array if it not at least of length N.
Because N grows by one each iteration, you could initialize as an empty array before the loop, and append(0) inside the loop:
sums = []
for N in range(1, len(n)+1):
sums.append(0)
I don’t particularly like the use of enumerate here either, I would:
for index in range(N)
sums[index] += (index + 1)**p
(Notice the +1 on the index that was missing in the code in the OP!)
Finally, n is just confusing here. I would:
for N in range(1, points + 1):
…

Use list comprehensions to make a list of count of elements smaller than the element in an array

I was solving this leetcode problem - https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
I solved it easily by using nested for loops but list comprehensions have always intrigued me. Ive spent a lot of time to make that one liner work but I always get some syntax error.
here's the solution:
count = 0
ans = []
for i in nums:
for j in nums:
if i > j:
count = count + 1
ans.append(count)
count = 0
return ans
these were the ones so far I think shouldve worked:
return [count = count + 1 for i in nums for j in nums if i > j]
return [count for i in nums for j in nums if i > j count = count + 1]
return [count:= count + 1 for i in nums for j in nums if i > j]
Ill also be happy if there's some resource or similar to put it together, Ive been searching the python docs but didnt find something that'll help me
I will transform the code step by step in order to show the thought process.
First: we don't care what the value of count is afterward, but we need it to be 0 at the start of each inner loop. So it is simpler logically to set it there, rather than outside and then also at the end of the inner loop:
ans = []
for i in nums:
count = 0
for j in nums:
if i > j:
count = count + 1
ans.append(count)
return ans
Next, we focus on the contents of the loop:
count = 0
for j in nums:
if i > j:
count = count + 1
ans.append(count)
A list comprehension is not good at math; it is good at producing a sequence of values from a source sequence. The transformation we need to do here is to put the actual elements into our "counter" variable1, and then figure out how many there are (in order to append to ans). Thus:
smaller = []
for j in nums:
if i > j:
smaller.append(j)
ans.append(len(smaller))
Now that the creation of smaller has the right form, we can replace it with a list comprehension, in a mechanical, rule-based way. It becomes:
smaller = [j for j in nums if i > j]
# ^ ^^^^^^^^^^^^^ ^^^^^^^^
# | \- the rest of the parts are in the same order
# \- this moves from last to first
# and then we use it the same as before
ans.append(len(smaller))
We notice that we can just fold that into one line; and because we are passing a single comprehension argument to len we can drop the brackets2:
ans.append(len(j for j in nums if i > j))
Good. Now, let's put that back in the original context:
ans = []
for i in nums:
ans.append(len(j for j in nums if i > j))
return ans
We notice that the same technique applies: we have the desired form already. So we repeat the procedure:
ans = [len(j for j in nums if i > j) for i in nums]
return ans
And of course:
return [len(j for j in nums if i > j) for i in nums]
Another popular trick is to put a 1 in the output for each original element, and then sum them. It's about the same either way; last I checked the performance is about the same and I don't think either is clearer than the other.
Technically, this produces a generator expression instead. Normally, these would be surrounded with () instead of [], but a special syntax rule lets you drop the extra pair of () when calling a function with a single argument that is a generator expression. This is especially convenient for the built-in functions len and sum - as well as for any, all, max, min and (if you don't need a custom sort order) sorted.
Hmm, three people write sum solutions but every single one does sum(1 for ...). I prefer this:
[sum(j < i for j in nums) for i in nums]
Instead of trying to advance an external counter, try adding ones to your list and then sum it:
for example:
nums = [1,2,3,4,5]
target = 3
print(sum(1 for n in nums if n < target))
Using counter inside the list comprehension creates the challenge of resetting it's value, each iteration of the first loop.
This can be avoided by filtering, and summing, in the second loop:
You use the first loop to iterate over the values of nums array.
return [SECOND_LOOP for i in nums]
You use the second loop, iterating over all elements of nums array. You filter in the elements that are smaller than i, the current element in the first loop, with if i < j, and evaluating 1 for each of them. Finally, you sum all the 1s generated:
sum(1 for j in nums if i > j)
You get the number of values that meet the requirements, by the list comprehension of the first loop:
return [sum(1 for j in nums if i > j) for i in nums]
This solution has been checked & validated in LeetCode.
You need a slightly different approach for the inner loop than a list comprehension. Instead of repeatedly appending a value to a list you need to repeatedly add a value to a variable.
This can be done in a functional way by using sum and a generator expression:
count = 0
# ...
for j in nums:
if i > j:
count = count + 1
can be replaced by
count = sum(1 for j in nums if i > j)
So that we now have this:
ans = []
for i in nums:
count = sum(1 for j in nums if i > j)
ans.append(count)
return ans
This pattern can in fact be replaced by a list comprehension:
return [sum(1 for j in nums if i > j) for i in nums]
Alternative Solution
We can also use the Counter from collections:
class Solution:
def smallerNumbersThanCurrent(self, nums):
count_map = collections.Counter(nums)
smallers = []
for index in range(len(nums)):
count = 0
for key, value in count_map.items():
if key < nums[index]:
count += value
smallers.append(count)
return smallers

List index out of bounds and stack overflow error

I am trying to get the max pair wise product using python this time around and the concepts of certain aspects are still new to me. I continue to get a list index out of bounds error and stackoverflows of which I do not know how to deal with given the fact that I can not choose types in Python.
I looked into enumerate and other iterate(ble) functions but to no avail. Id answered this could help future people with simple for loop questions in migration from C to python.
def max_pairwise_product(numbers):
n = len(numbers)
max_product = 0
for first in range(n):
for second in range(first + 1, n):
max_product = max(max_product,
numbers[first] * numbers[second])
return max_product
def max_pairwise_product_fast(numbers):
n = len(numbers)
index1 = 1
for i in range(2,n,1):
if (numbers[i]>numbers[index1]):
index1 = i
if (index1 == 1):
index2 = 2
else:
index2=1
for i in range(1,n):
if(numbers[i]!=numbers[index1] and numbers[i]>numbers[index2]):
index2 = i
return (numbers[index1]*numbers[index2])
if __name__ == '__main__':
input_n = int(input())
input_numbers = [int(x) for x in input().split()]
print(max_pairwise_product_fast(input_numbers))
Traceback (most recent call last):
File "C:/Users/Tevin/.PyCharmCE2018.3/config/scratches/scratch_1.py", line 31, in <module>
print(max_pairwise_product_fast(input_numbers))
File "C:/Users/Tevin/.PyCharmCE2018.3/config/scratches/scratch_1.py", line 27, in max_pairwise_product_fast
return (numbers[index1]*numbers[index2])
IndexError: list index out of range
why dont you find the 2 max numbers in your list and multiply them to get the max product. find the max of list then save it in some variable. remove it from the list and find the max again. then multiply this with your saved variable.
as for your code, what is this line for?
input_n = int(input())
you are not using the input_n variable anywhere.
and the line:
input_numbers = [int(x) for x in input().split()]
your code will ask you for 2 inputs. when you first enter your input, it is saved in the input_n variable. then your second input is saved as input_numbers. something is wrong with the type of input you are giving the program.
If I understand your max_pairwise_product_fast correctly, you are trying to find the largest and second largest number and multiply them. The problem is that you initialize index1 as 1, and index2 with 1 or 2, but array-indexes start with 0. Thus, your code will fail for a list with only two elements, e.g. [1,2]. Change the starting indices to 0, and change the range in the loops accordingly, and it will work.
You can also remove some of the checks, e.g. the if/else, as that's redundant with the check you have in your second loop. Also, by comparing number[index1] and number[index2] you could miss the highest product if the highest number appears twice, e.g. [1,2,2].
Staying close to your original code, you can try this:
def max_pairwise_product_fast(numbers):
n = len(numbers)
index1 = 0
for i in range(n):
if numbers[i] > numbers[index1]:
index1 = i
index2 = 0
for i in range(n):
if index2 != index1 and numbers[i] > numbers[index2]:
index2 = i
return numbers[index1] * numbers[index2]
But you could also use max instead of those two loops:
def max_pairwise_product_fast(numbers):
n = len(numbers)
index1 = max(range(n), key=lambda i: numbers[i])
index2 = max((i for i in range(n) if i != index1), key=lambda i: numbers[i])
return numbers[index1] * numbers[index2]
Or sort the entire array and pick the highest two:
def max_pairwise_product_fast(numbers):
second, first = sorted(numbers)[-2:]
return first * second
Note, however, that this might still fail if the list includes negative numbers, e.g. [1, 2, -3, -4]. For this, you could call the same function again with all the numbers in the list negated and pick the higher of the two results.

Python: Editing list while iterating over it

There are some related questions on Stack but I wanted to be as clear as possible. I am using Python 3
If I have a list, N, and I use the following code:
N = [1,2,3,4,6,7,8]
for x in N:
N[x] = N[x] * -1
return N
I am getting a Index out of range error. I understand you shouldn't be adding and deleting elements while iterating over a list, but I wanted a clear definition of why the above example won't work.To me, it seems like there shouldn't be a problem. In the first iteration, x should evaluate to 1. So if I want to edit N[1], I don't see why I wouldn't be able to.
As a side note, I know enumerate() is the proper way to do it.
Use enumerate
Ex:
N = [1,2,3,4,6,7,8]
for x, value in enumerate(N):
N[x] = value * -1
print(N)
or a list comprehension.
Ex:
N = [x * -1 for x in N]
In for x in N:, x takes on each value in N, then you use it like an index. Lists in Python are 0-indexed, so you get an Index out of range error when you reach the end of the list and try to access N[8], which doesn't exist. You can use for x in range(len(N)): instead.
The problem here is actually a little different: you're treating members of the list as if they were indices of the list. Since N[8] doesn't exist, that's where your error is coming from. I think what you meant to do was:
N = [1,2,3,4,6,7,8]
for x in range(len(N)):
N[x] = N[x] * -1
return N
In the first iteration, x=1 which means N[1] equals 2 and so your new N[1] becomes 2 * -1 = -2. Now when x is 8 since you are using for x in N, your code tries to access N[8] but since the length of N is 8, the indexing starts from 0 and goes up to 7. Hence there is no index 8 and hence you get an error Index out of range error
Use good ol' lambda's or a specific callable in list comprehension:
lambda:
N = [1,2,3,4,6,7,8]
M = [(lambda x:-x)(element) for element in N]
print(M)
callable/function:
def negate(x):
return -x
N = [1,2,3,4,6,7,8]
M = [negate(element) for element in N]
print(M)
In your code here -
N = [1,2,3,4,6,7,8]
for x in N:
# x will be 1, 2, 3, 4
And the way you are accessing is -
N[x]
But indices run from 0 to n-1, where n-1 is the last element. Also, in your list, you are missing a 5 so indices will change badly. If you had
N = [1,2,3,4,5,6,7,8]
your code would have worked fine. But since that's not the case, you'd have to use range like -
for i in range(len(N)):
N[i] = N[i] * -1
You are enumerating in a wrong way
N = [1,2,3,4,6,7,8]
for i, x in enumerate(N):
N[i] = N[i] * -1
return N

Getting index error in the code in python

def fact(n):
fac = 1
while (n>1):
fac = fac*n
n -= 1
return fac
z = 0
t = int(raw_input())
nz = []
for i in range(0,t):
c = 0
n = int(raw_input())
z = fact(n)
z = list(str(z))
for j in range(len(z)-1,1,-1):
if z[j] != '0':
break
else:
c +=1
nz[i].append(c)
for k in range(0,t):
print nz[k]
Hello I am getting
Indexerror : index out of range at " nz[i].append(c)
This program should calculate trailing zeros in the factorial of N.
Can you also please help me optimize my code, so it can run also for large values of N?
nz is empty list. It doesn't have any elements, so nz[i] would always raise IndexError. Perhaps you meant nz.append(c) ie. add c at the end of nz.
This is how does append() work:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
so you may want to change nz[i].append(c) to nz.append(c), since your i index is already handled by the append function. You're actually assuming you have an i element in your list, which is false, since you are using an empty list
About optimizing, your problem is probably due to your recursion limit. Try import sys; sys.getrecursionlimit() in your python shell, you should see something like 1000 as result.
Swapping for an iterative version of the factorial function could be a start
def fact(n):
r = 1
for x in range (n):
r = r * (x+1)
return r

Categories

Resources