python 3 confusion about making copy of a list using [:] - python-3.x

assume L is a list f and g are defined function
def function(L,f,g):
newL = list()
for i in L:
if g(f(i)) == True:
newL.append(i)
L[:] = newL
if len(L) == 0:
return -1
else:
return max(L)
def f(i):
return i + 2
def g(i):
return i > 5
L = [0, -10, 5, 6, -4]
print(function(L, f,g))
print(L)
Using L = newL[:] will cause print(L) to print L = [0, -10, 5, 6, -4].
But if inside function I use L[:] = newL, print(L), this will make print(L) give me the result of newL [5,6] - which is what I want
To me, both L = newL[:] and L[:] = newL will give me the same result. But in reality, it did not. So, can anyone provide me an explanation of this?

It's a scope issue. Lists created in the global space are changeable within a function because with this line:
L[:] = newL
you are operating on a reference to the global list, not a local copy of it. Therefore, the last line of your program prints the changed list. Whereas this version:
L = newL[:]
...is operating on a local copy of the list, so the last line of your program prints the global as it was before the function call.
Play around with this modified version:
def function(L,f,g):
newL = list()
for i in L:
if g(f(i)) == True:
newL.append(i)
L = newL[:]
#L[:] = newL
print('inner L = ', L)
if len(L) == 0:
return -1
else:
return max(L)
def f(i):
return i + 2
def g(i):
return i > 5
L = [0, -10, 5, 6, -4]
print(function(L, f,g))
print('outer L =', L)

Related

i tried this code but it did not work, what should i change?

i wrote this solution to the problem:
The function should create a new empty list and add every element from lst that has an odd index. The function should then return this new list.
For example, odd_indices([4, 3, 7, 10, 11, -2]) should return the list [3, 10, -2].
solution: i'm a beginner, i can't understand why this returns 10 only instead of 3, 10, -2.
def odd_indices(lst):
new_lst = []
for i in lst:
if i % 2 != 0:
new_lst.append(lst[i])
return new_lst
#this is python 3
def odd_indices(lst):
new_lst = []
for i in lst:
if i % 2 != 0:
new_lst.append(lst[i])
return new_lst
return makes the function exit immediately. Un-indent the return statement so it is not inside the for loop.
def odd_indices(lst):
new_lst = []
for i in lst:
if i % 2 != 0:
new_lst.append(lst[i])
return new_lst # <---------- unindent here

return statement of while loop and logic issues

I am embarrassed to ask this but I cannot seem to return the correct result for the function. Basically I can program the function to handle a solution or no solution but not both.
def sum_pair(l, t):
l.sort()
s = 0 # start index
e = len(l) - 1 # last index
while s < e:
if (l[s] + l[e] == t):
a, b = l[s], l[e]
return a, b
elif (l[s] + l[e] < t):
s = + 1
else:
e -= 1
return a,b # return (0,0) !no result or return (n,n) if result
l1 = [4, 3, 5, 7, 8]
target = 20 # No solution
print(sum_pair(l1, target))
Basically I'm trying to return (0,0) if there is no solution but I need it to return (n,n) if they sum to the target value. I would like to avoid the conditional logic if possible.
My guess is that I have a scope issue.
Thanks to anyone in advance.
No need of a and b in this problem
There is a typo in s = + 1 which will be s+=1
def sum_pair(l, t):
l.sort()
s = 0 # start index
e = len(l) - 1 # last index
while s < e:
if l[s] + l[e] == t:
return l[s], l[e]
elif l[s] + l[e] < t:
s += 1
else:
e -= 1
return 0,0 # return (0,0) !no result or return (n,n) if result
l1 = [4, 3, 5, 7, 8]
target = 20 # No solution
print(sum_pair(l1, target))
This works fine for me.
Here is how I edited your code:
def sum_pair(l, t):
l.sort()
s = 0 # start index
e = len(l) - 1 # last index
a, b = 0, 0 # set default return value
while s < e:
if (l[s] + l[e] == t):
a, b = l[s], l[e]
break
elif (l[s] + l[e] < t):
s += 1 # you typoed this line
else:
e -= 1
return a, b
l1 = [4, 3, 5, 7, 8]
target = 10 # No solution
print(sum_pair(l1, target))
I'm not exactly sure what should happen in case there are multiple answers. This way it accepts the pair with the smallest value for a.

Why is this BFS queue returning None?

I am currently attempting the Hackerrank problem called Castle on the Grid,
in which I have implemented a BFS in Python 3 as follows:
#!/bin/python3
import math
import os
import random
import re
import sys
from collections import deque
def minimumMoves(grid, startX, startY, goalX, goalY):
n = len(grid)
queue = deque()
queue.append((startY,startX))
goal = (goalY,goalX)
turnsMatrix = [[0]*n]*n
while queue:
current = queue.popleft()
(Y0, X0) = current
print(current)
d = turnsMatrix[Y0][X0]
if current == goal:
return(d)
for X in range(X0-1,-1,-1):
if grid[Y0][X] == 'X':
break
elif turnsMatrix[Y0][X] == 0:
turnsMatrix[Y0][X] = d + 1
queue.append((Y0,X))
for Y in range(Y0-1,-1,-1):
if grid[Y][X0] == 'X':
break
elif turnsMatrix[Y][X0] == 0:
turnsMatrix[Y][X0] = d + 1
queue.append((Y,X0))
for X in range(X0+1,n):
if grid[Y0][X] == 'X':
break
elif turnsMatrix[Y0][X] == 0:
turnsMatrix[Y0][X] = d + 1
queue.append((Y0,X))
for Y in range(Y0+1,n):
if grid[Y][X0] == 'X':
break
elif turnsMatrix[Y][X0] == 0:
turnsMatrix[Y][X0] = d + 1
queue.append((Y,X0))
if __name__ == '__main__':
fptr = open(os.environ['OUTPUT_PATH'], 'w')
n = int(input())
grid = []
for _ in range(n):
grid_item = input()
grid.append(grid_item)
startXStartY = input().split()
startX = int(startXStartY[0])
startY = int(startXStartY[1])
goalX = int(startXStartY[2])
goalY = int(startXStartY[3])
result = minimumMoves(grid, startX, startY, goalX, goalY)
fptr.write(str(result) + '\n')
fptr.close()
However, despite only one return statement which is supposed to return an int d, my code returns a None. I know that the deque eventually becomes empty and returns None, but I am having trouble figuring out why things stop appending to the queue.
For the test case
3
.X.
.X.
...
0 0 0 2
I noticed that what would happen is:
1) castle moves right and breaks at X.
2) castle moves down one cell, and the turns matrix becomes
[[1, 0, 0], [1, 0, 0], [1, 0, 0]].
3) queue becomes deque([(1, 0)]).
4) A None is returned.
What is going on? I've been staring at my code for days and I'm going crazy... please help, thank you!

Program thats asks for a number then prints out all its factors, 150 --> 2,3,5,5

n = int(input("What number do you want factored out"))
def factors(n):
for i in range(2,n):
if n % i == 0:
return i
n = n/i
return factors(n)
print(factors(n))
I'm currently using the current code, however I can only get the first factor. Can I not use recursion to repeat the code and generate all factors?
Is there a better way to approach this question?
Use a while loop instead:
def factors(n):
f = []
while n != 1:
for i in range(2, n + 1):
if n % i == 0:
f.append(i)
n //= i
break
return f
print(factors(150))
Or, with recursion:
def factors(n):
if n == 1:
return []
for i in range(2, n + 1):
if n % i == 0:
return [i] + factors(n // i)
print(factors(150))
Both output:
[2, 3, 5, 5]
The return keyword essentially terminates the execution of the function. Any statements immediately following a return statement will never be reached. So as soon as you find a factor and do return i, your function ends. Maybe you're confusing return i and print i? Alternatively, add it to an array and pass that down through the next recursive function call.
This can be done recursively, but it's probably best to do this algorithm iteratively because it's faster and more readable:
def factors(n):
for i in range(1, int(n ** 0.5) + 1):
if n % i == 0:
yield i
yield n // i
print(list(factors(25)))
This is far from industrial strength but should be reasonably fast. It allows duplicates, so you may wish to call set() before list(). You only need to iterate up to the square root of n and for any number i that is a factor, include the number that can be multiplied by i to get n as well.
if you want all the factors then you can do:
import numpy as np
fact = lambda x : np.arange(1,x+1)[x % np.arange(1,x+1)==0]
fact(100)
array([ 1, 2, 4, 5, 10, 20, 25, 50, 100])
fact(27)
array([ 1, 3, 9, 27])
if you just want the prime multipliers:
def facts(x,m=None,i=2):
if m is None:
m = []
if x //i >0:
if x % i ==0:
m.append(i)
facts(x // i,m ,i)
else:
facts(x,m,i+1)
return(m)
facts(150)
[2, 3, 5, 5]
facts(2*3*5*7*9*10)
[2, 2, 3, 3, 3, 5, 5, 7]

Reduce time complexity of program

I have written a function to remove items specified in a given list.
def remove_given_elements(arr1) :
b = []
x = int(input("Enter the number of items to be removed :"))
for i in range(x) :
y = int(input("Enter the position to be removed :"))
b.append(y)
arr3 = []
pos = 0
for i in range(len(arr1)) :
arr3.append(arr1[i])
for j in range(len(b)):
if pos == b[j]:
arr3.pop(b[j])
arr3.append(None)
pos += 1
arr4 = []
for i in arr3:
if i != None :
arr4.append(i)
return arr4
a = [100,200,323,434,512,656]
print("After removing elements",remove_given_elements(a))
Output :
Enter the number of items to be removed :3
Enter the position to be removed :1
Enter the position to be removed :3
Enter the position to be removed :4
After removing elements [100, 323, 656]
As, i am new to programming. I really don't know any methods to decrease my worst case time complexity. Any kind of help is appreciated or please guide me to use proper methods which decreases time complexity.
You can ask before for the positions and store them in a tuple. Then apply the function.
def remove(_list, pos):
return [v for i, v in enumerate(_list) if i not in pos]
positions = (1, 2, 3)
l = [1, 2, 3, 4, 5, 6, 7]
result = remove(l, positions)
print(result)
The function return a List Comprehension

Resources