I just started learning python with small scripts. I came across a quiz to determine a list to be symmetric if the first row is the same as the first column,
the second row is the same as the second column and so on.
def symmetric(block):
n = len(block)
i = 0
for i in range(n-1):
j = 0
for j in range(n-1):
if (block[i][j] != block[j][i]):
return False
j +=1
i +=1
return True
So the result of
print symmetric([["cat", "dog", "fish"],
["dog", "dog", "dog"],
["fish","fish","cat"]])
should be False.
However, this code always return True, and in debugger I can see block[i][j] != block[j][i] returns True but the if block is not executed. Is there anything wrong with the comparison or the if block is not correctly composed?
The main reason why it fails is because you should write range(n) instead of range(n-1) (the upperbound is exclusive). Like:
def symmetric(block):
n = len(block)
for i in range(n):
for j in range(n):
if block[i][j] != block[j][i]:
return False
return True
Nevertheless, there are several weird things about this function:
you initialize i = 0 and j = 0. That is not necessary: in Python, the for loop will declare the variable for you;
you perform increments/decrements on i and j, this is again not necessary. A for loop enumerates over the iterable/generator and assigns each value to i and j;
usually one does not write parenthesis for if statements.
Furthermore you can actually make this code more elegant using a two-liner with the all(..) builtin function:
def symmetric(block):
n = len(block)
return all(block[i][j] == block[j][i] for i in range(n) for j in range(n))
This is a more declarative and more explicit style of writing code. Since here the code is almost self-explaining: "return whether all block[i][j] == block[j][i] for i in range(n) and for j in range(n)"
Finally like #Błotosmętek says in their comment, you do not have to check block[2][0] == block[0][2] if you have already checked block[0][2] == block[2][0]. So you can improve performance (about half) by writing:
def symmetric(block):
n = len(block)
return all(block[i][j] == block[j][i] for i in range(n) for j in range(i))
You should use range(n) rather than range(n-1); sequences generated by range do not include the upper bound.
def symmetric(block):
n = len(block)
for i in range(n):
for j in range(n):
print i, j
if (block[i][j] != block[j][i]):
return False
return True
print symmetric([["cat", "dog", "fish"],
["dog", "dog", "dog"],
["fish","fish","cat"]])
In python you don't have to declare or increment the variable used for looping, python "for-loop" is intelligent enough to do it for us.
You also have to study how the range function works in python, range() can be called in three ways,
range(N-number of times to loop): range will return a list of N integers starting from 0 to N-1.
range(S-start position, N-end position): In this case range will return a list of (N-S) integers starting from S to N-1.
range(S-start position, N-end position, K-steps): here range will return a list of (N-S)/K integers starting from S to N-1 with an interval of K.
In your case when you said range(n-1) your loop was iterating only on indices 0,1 skipping index 2, no wonder you were getting True every time.
Related
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)
I have to create a function that have to return true if a row in that matrix have no multiple ocurrences and false otherwise. This have to be done by loops, then create the same function with recursion. I was able to do the function using loops below but I just could think how it could be done by recursion.
def IsnonrepeatedRow(A):
count = 0
for i in range(len(A)):
for x in range (i+1, len(A)):
for j in range(len(A[0])):
if A[i][j] // A[x][j] == 0:
count += 1
if count == len(A[0]):
return True
count = 0
return False
Basically all you need depends on the "count" value. Therefore you should pass it recursively for each column, add 1 if equals to zero, and at the end of the column check your current condition.
Overall, should not be so different from your current algorithm. The difference is only by passing "count" through recursion.
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
so if the function is:
function(n)
what can i do to if i want.
function(5)
to return as
1
2
3
4
5
I'm thinking towards creating an empty list, but i don't know what to append into the list to get the number 1 up to 'n'
You can try
def function(n):
for x in range(0, n):
print x+1
if you want to print the values, or
def function(n):
returnlist = []
for x in range(0, n):
returnlist.append(x+1)
return returnlist
to return a list.
The for x in range(0, n): part of the code is called a for loop. It repeats itself n times, and x is incremented by one each time is repeats. You can then use x to accomplish different tasks within your code. In this case, we're simply taking its value plus one and printing it or appending it to a list. We have to add one to the value because x is zero based, although it doesn't have to be. We could just as easily have written for x in range(1, n+1): and not have had to add one to the x value.
Here is a simple example:
def function(n):
for i in range(1, n+1):
print i
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