Python list comprehension with rockets - python

I need to print out a list of rockets with their own positions (x and y) using list comprehension (need to use list comprehension for homework).
I have an issue currently when I print the list, it first prints (0,0) for 9 times before it prints the assigned x and y values for each rocket. I am very new to python, so please bear with me.
class Rocket:
## Fill in the rest of the class definition
def __init__ (self, x=0,y=0):
self.x = x
self.y = y
def moveup(self):
self.y += 1
rocket = Rocket(0,0)
print("Starting position is " , rocket.x, rocket.y)
direction = input("What direction do you want to go?")
if direction == "up":
print("you went up")
rocket.moveup()
print("Position: ", rocket.x, rocket.y)
else:
print("Nothing happened")
#-------------------------------------------------------------------------------------
rockets = [Rocket() for x in range(0,10)]
rockets.append(Rocket(0,0))
rockets.append(Rocket(1,1))
rockets.append(Rocket(2,2))
rockets.append(Rocket(3,3))
rockets.append(Rocket(4,4))
rockets.append(Rocket(5,5))
rockets.append(Rocket(6,6))
rockets.append(Rocket(7,7))
rockets.append(Rocket(8,8))
rockets.append(Rocket(9,9))
for rocket in rockets:
print(rocket.x,rocket.y)
my output is :
Starting position is 0 0
What direction do you want to go?up
you went up
Position: 0 1
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
I think I partially know what is going on, when I first make the list it makes, each rocket 0,0 and when I append, it creates a new rocket instead of editing them. I guess my main question is how do I edit an index of the array to correct this?

You don't need the list comprehension and the appends. Just initialize the list with the rockets you want in the list comprehension
rockets = [Rocket(i, i) for i in range(10)]

please observe that when calling
rockets = [Rocket() for x in range(0,10)]
you create 10 instances of class Rocket and put them on the list rockets. Call is supplied with no parameters an thus default values are used as defined in constructor (Rocket: ... def __init__ (self, x=0,y=0)).
This is equivalent to calling rockets.append(Rocket(0, 0)) 10 times. Then you create the remaining 10 by hand
rockets.append(Rocket(0,0))
...
rockets.append(Rocket(9,9))
so the output is justified
and when I append, it creates a new rocket instead of editing them
That`s exactly what it does .You may want to use array subscription to get the object from an array to use its methods or edit its properties
e.g.
for r in rockets:
r.moveup()
for r in rockets:
r.x = r.y*r.y

Related

Return a pandas series from a loop

I have a pandas dataframe nike that looks like this:
rise1 run1 position
1 0.82 1
3 1.64 2
5 3.09 3
7 5.15 4
8 7.98 5
15 11.12 6
I am trying to make a function that calculates grade (rise/run) and returns it as a pandas series. I want to use X points ahead of the current position minus X points behind the current position to calculate grade (i.e. if X = 2, the grade at position 4 is (15-3)/(11.12-1.64)).
def get_grade(dataf, X=n):
grade = pd.Series(data = None, index = range(dataf.shape[0]))
for i in range(X, dataf.shape[0] - X):
rise = dataf.loc[i + X, 'rise1'] - dataf.loc[i - X,'rise1']
run = dataf.loc[i + X, 'run1'] - dataf.loc[i - X, 'run1']
if np.isclose(rise, 0) or np.isclose(run, 0):
grade[i] = 0
elif rise / run > 1:
grade[i] = 1
elif rise / run < -1:
grade[i] = -1
else:
grade[i] = rise / run
return grade
get_grade(nike, X= 2)
When I call the function, nothing happens. The code executes but nothing appears. What might I be doing wrong? Apologies if this is unclear, I am very new to coding in general with limited vocab in this area.
You have to set a variable equal to the function (so setting the variable equal to your return value) and then print/display that variable. Like df = get_grade(nike, X= 2) print(df). Or put a print call in your function
def test_function():
df = pd.DataFrame({"col1":[1,2,3,4], "col2":[4,3,2,1]})
return df
df = test_function()
print(df)
Or
def test_print_function():
df = pd.DataFrame({"col1":[1,2,3,4], "col2":[4,3,2,1]})
print(df)
test_print_function()
The way you are working is suboptimal. In general, a for loop + .loc in pandas repeatedly is a signal that you're not taking advantage for the framework.
My suggestion is to use a rolling window, and apply your calculations:
WINDOW = 2
rolled = df[['rise1', 'run1']].rolling(2*WINDOW + 1, center=True)\
.apply(lambda s: s.iloc[0] - s.iloc[-1])
print(rolled['rise1'] / rolled['run1'])
0 NaN
1 NaN
2 0.977654
3 1.265823
4 NaN
5 NaN
dtype: float64
Now, as to your specific problem, I cannot reproduce. Copying and pasting your code in a brand new notebook works fine, but apparently it doesn't yield the results you want (i.e. you don't find (15-3)/(11.12-1.64) as you intended).

Python not copying variable user-defined class but making pointer instead [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 2 years ago.
I was trying to make chess playing algorithm that "bruteforces" possible options and choosing the best.
To do this, I wrote class, which represents board situation on board(showed the parts that used in bad code).
class Chess:
def __init__(self):
#Here is the board 2D array - enemy is downside.
self.board = [[ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK], [PAWN for i in range(8)], [EMPTY for i in range(8)], [EMPTY for i in range(8)], [EMPTY for i in range(8)], [EMPTY for i in range(8)], [ENEMYPAWN for i in range(8)], [ENEMYROOK, ENEMYKNIGHT, ENEMYBISHOP, ENEMYKING, ENEMYQUEEN, ENEMYBISHOP, ENEMYKNIGHT, ENEMYROOK]]
def WriteBoard(self):
WriteBoard(self.board)
def Moove(self, x1, y1, x2, y2):
if x1 >= 8 or x1 < 0 or x2 >= 8 or x2 < 0 or y1 >= 8 or y1 < 0 or y2 >= 8 or y2 < 0:
raise IndexError("Parameter is not correct.")
return
#WARNING: Not checking if moove correct.
self.board[y2][x2] = self.board[y1][x1]
self.board[y1][x1] = EMPTY
Where:
EMPTY = 0
PAWN = 2
ROOK = 17
KNIGHT = 10
BISHOP = 14
QUEEN = 45
KING = 60
ENEMYPAWN = -2
ENEMYROOK = -17
ENEMYKNIGHT = -10
ENEMYBISHOP = -14
ENEMYQUEEN = -45
ENEMYKING = -60
...Next part is function that returns possible moves getting Chess variable and x, y as parameters:
def PossibleMooves(chessBoard, x, y):
possibleMooves = []
target = chessBoard.board[y][x]
if target == EMPTY:
return possibleMooves
helpVar = chessBoard
if target == PAWN:
try:
if helpVar.board[y + 1][x] == EMPTY:
helpVar.Moove(x, y, x, y + 1)
possibleMooves += [res]
index += 1
helpVar = chessBoard
except IndexError as e:
... #print(e)
elif target == ROOK:
...
... #And so on...
return possibleMooves
Please note that try...except statement helps to establish correctness of move(index like [y + 1][x] can not exist)
But the problem is:
Variable chessBoard changing together with helpVar, and variable that were given to function.
You can check it with this code:
chess = Chess()
print(chess.board[1][1])
results = PossibleMooves(chess, 1, 1)
print(chess.board[1][1])
Output should be:
2
2
But its:
2
0
helpVar = chessBoard means that every change you make to helpVar will be reflected in chessBoard. They point to the same object. If you want to avoid it - clone chessBoard and work with a copy.
See here about copy in python. (Look at deepcopy)

Kosaraju's Algorithm for SCCs, non-recursive

I have an implementation of Kosaraju's algorithm for finding SCCs in Python. The code below contains a recursive (fine on the small test cases) version and a non-recursive one (which I ultimately need because of the size of the real dataset).
I have run both the recursive and non-recursive version on a few test datasets and get the correct answer. However running it on the much larger dataset that I ultimately need to use, produces the wrong result. Going through the real data is not really an option because it contains nearly a million nodes.
My problem is that I don't know how to proceed from here. My suspision is that I either forgot a certain case of graph constellation in my test cases, or that I have a more fundamental misunderstanding about how this algo is supposed to work.
#!/usr/bin/env python3
import heapq
class Node():
"""A class to represent nodes in a DirectedGraph. It has attributes for
performing DFS."""
def __init__(self, i):
self.id = i
self.edges = []
self.rev_edges = []
self.explored = False
self.fin_time = 0
self.leader = 0
def add_edge(self, edge_id):
self.edges.append(edge_id)
def add_rev_edge(self, edge_id):
self.rev_edges.append(edge_id)
def mark_explored(self):
self.explored = True
def set_leader(self, leader_id):
self.leader = leader_id
def set_fin_time(self, fin_time):
self.fin_time = fin_time
class DirectedGraph():
"""A class to represent directed graphs via the adjacency list approach.
Each dictionary entry is a Node."""
def __init__(self, length, list_of_edges):
self.nodes = {}
self.nodes_by_fin_time = {}
self.length = length
self.fin_time = 1 # counter for the finishing time
self.leader_count = 0 # counter for the size of leader nodes
self.scc_heapq = [] # heapq to store the ssc by size
self.sccs_computed = False
for n in range(1, length + 1):
self.nodes[str(n)] = Node(str(n))
for n in list_of_edges:
ns = n[0].split(' ')
self.nodes[ns[0]].add_edge(ns[1])
self.nodes[ns[1]].add_rev_edge(ns[0])
def n_largest_sccs(self, n):
if not self.sccs_computed:
self.compute_sccs()
return heapq.nlargest(n, self.scc_heapq)
def compute_sccs(self):
"""First compute the finishing times and the resulting order of nodes
via a DFS loop. Second use that new order to compute the SCCs and order
them by their size."""
# Go through the given graph in reverse order, computing the finishing
# times of each node, and create a second graph that uses the finishing
# times as the IDs.
i = self.length
while i > 0:
node = self.nodes[str(i)]
if not node.explored:
self.dfs_fin_times(str(i))
i -= 1
# Populate the edges of the nodes_by_fin_time
for n in self.nodes.values():
for e in n.edges:
e_head_fin_time = self.nodes[e].fin_time
self.nodes_by_fin_time[n.fin_time].add_edge(e_head_fin_time)
# Use the nodes ordered by finishing times to calculate the SCCs.
i = self.length
while i > 0:
self.leader_count = 0
node = self.nodes_by_fin_time[str(i)]
if not node.explored:
self.dfs_leaders(str(i))
heapq.heappush(self.scc_heapq, (self.leader_count, node.id))
i -= 1
self.sccs_computed = True
def dfs_fin_times(self, start_node_id):
stack = [self.nodes[start_node_id]]
# Perform depth-first search along the reversed edges of a directed
# graph. While doing this populate the finishing times of the nodes
# and create a new graph from those nodes that uses the finishing times
# for indexing instead of the original IDs.
while len(stack) > 0:
curr_node = stack[-1]
explored_rev_edges = 0
curr_node.mark_explored()
for e in curr_node.rev_edges:
rev_edge_head = self.nodes[e]
# If the head of the rev_edge has already been explored, ignore
if rev_edge_head.explored:
explored_rev_edges += 1
continue
else:
stack.append(rev_edge_head)
# If the current node has no valid, unexplored outgoing reverse
# edges, pop it from the stack, populate the fin time, and add it
# to the new graph.
if len(curr_node.rev_edges) - explored_rev_edges == 0:
sink_node = stack.pop()
# The fin time is 0 if that node has not received a fin time.
# Prevents dealing with the same node twice here.
if sink_node and sink_node.fin_time == 0:
sink_node.set_fin_time(str(self.fin_time))
self.nodes_by_fin_time[str(self.fin_time)] = \
Node(str(self.fin_time))
self.fin_time += 1
def dfs_leaders(self, start_node_id):
stack = [self.nodes_by_fin_time[start_node_id]]
while len(stack) > 0:
curr_node = stack.pop()
curr_node.mark_explored()
self.leader_count += 1
for e in curr_node.edges:
if not self.nodes_by_fin_time[e].explored:
stack.append(self.nodes_by_fin_time[e])
###### Recursive verions below ###################################
def dfs_fin_times_rec(self, start_node_id):
curr_node = self.nodes[start_node_id]
curr_node.mark_explored()
for e in curr_node.rev_edges:
if not self.nodes[e].explored:
self.dfs_fin_times_rec(e)
curr_node.set_fin_time(str(self.fin_time))
self.nodes_by_fin_time[str(self.fin_time)] = Node(str(self.fin_time))
self.fin_time += 1
def dfs_leaders_rec(self, start_node_id):
curr_node = self.nodes_by_fin_time[start_node_id]
curr_node.mark_explored()
for e in curr_node.edges:
if not self.nodes_by_fin_time[e].explored:
self.dfs_leaders_rec(e)
self.leader_count += 1
To run:
#!/usr/bin/env python3
import utils
from graphs import scc_computation
# data = utils.load_tab_delimited_file('data/SCC.txt')
data = utils.load_tab_delimited_file('data/SCC_5.txt')
# g = scc_computation.DirectedGraph(875714, data)
g = scc_computation.DirectedGraph(11, data)
g.compute_sccs()
# for e, v in g.nodes.items():
# print(e, v.fin_time)
# for e, v in g.nodes_by_fin_time.items():
# print(e, v.edges)
print(g.n_largest_sccs(20))
Most complex test case (SCC_5.txt):
1 5
1 4
2 3
2 11
2 6
3 7
4 2
4 8
4 10
5 7
5 5
5 3
6 8
6 11
7 9
8 2
8 8
9 3
10 1
11 9
11 6
Drawing of that test case: https://imgur.com/a/LA3ObpN
This produces 4 SCCs:
Bottom: Size 4, nodes 2, 8, 6, 11
Left: Size 3, nodes 1, 10, 4
Top: Size 1, node 5
Right: Size 3, nodes 7, 3, 9
Ok, I figured out the missing cases. The algorithm wasn't performing correctly on very strongly connected graphs and duplicated edges. Here is an adjusted version of the test case I posted above with a duplicated edge and more edges to turn the whole graph into one big SCC.
1 5
1 4
2 3
2 6
2 11
3 2
3 7
4 2
4 8
4 10
5 1
5 3
5 5
5 7
6 8
7 9
8 2
8 2
8 4
8 8
9 3
10 1
11 9
11 6

Issues with using np.linalg.solve in Python

Below, I'm trying to code a Crank-Nicholson numerical solution to the Navier-Stokes equation for momentum (simplified with placeholders for time being), but am having issues with solving for umat[timecount,:], and keep getting the error "ValueError: setting an array element with a sequence". I'm extremely new to Python, does anyone know what I could do differently to avoid this problem?
Thanks!!
def step(timesteps,dn,dt,Numvpts,Cd,g,alpha,Sl,gamma,theta_L,umat):
for timecount in range(0, timesteps+1):
if timecount == 0:
umat[timecount,:] = 0
else:
Km = 1 #placeholder for eddy viscosity
thetaM = 278.15 #placeholder for theta_m for time being
A = Km*dt/(2*(dn**2))
B = (-g*dt/theta_L)*thetaM*np.sin(alpha)
C = -dt*(1/(2*Sl) + Cd)
W_arr = np.zeros(Numvpts+1)
D = np.zeros(Numvpts+1)
for x in (0,Numvpts): #creating the vertical veocity term
if x==0:
W_arr[x] = 0
D[x] = 0
else:
W_arr[x] = W_arr[x-1] - (dn/Sl)*umat[timecount-1,x-1]
D = W_arr/(4*dn)
coef_mat_u = Neumann_mat(Numvpts,D-A,(1+2*A),-(A+D))
b_arr_u = np.zeros(Numvpts+1) #the array of known quantities
umat_forward = umat[timecount-1,2:Numvpts]
umat_center = umat[timecount-1,1:Numvpts-1]
umat_backward = umat[timecount-1,0:Numvpts-2]
b_arr_u = np.zeros(Numvpts+1)
for j in (0,Numvpts):
if j==0:
b_arr_u[j] = 0
elif j==Numvpts:
b_arr_u[j] = 0
else:
b_arr_u[j] = (A+D[j])*umat_backward[j]*(1-2*A)*umat_center[j] + (A-D[j])*umat_forward[j] - C*(umat_center[j]*umat_center[j]) - B
umat[timecount,:] = np.linalg.solve(coef_mat_u,b_arr_u)
return(umat)
Please note that,
for i in (0, 20):
print(i),
will give result 0 20 not 0 1 2 3 4 ... 20
So you have to use the range() function
for i in range(0, 20 + 1):
print(i),
to get 0 1 2 3 4 ... 20
I have not gone through your code rigorously, but I think the problem is in your two inner for loops:
for x in (0,Numvpts): #creating the vertical veocity term
which is setting values only at zero th and (Numvpts-1) th index. I think you must use
for x in range(0,Numvpts):
Similar is the case in (range() must be used):
for j in (0,Numvpts):
Also, here j never becomes == Numvpts, but you are checking the condition? I guess it must be == Numvpts-1
And also the else condition is called for every index other than 0? So in your code the right hand side vector has same numbers from index 1 onwards!
I think the fundamental problem is that you are not using range(). Also it is a good idea to solve the NS eqns for a small grid and manually check the A and b matrix to see whether they are being set correctly.

2d list or array: How do I modify one value - ie a unique pointer per cell?

How do I make a list with only one pointer per cell? (I think that is the problem)
Thanks
ps if you are feeling nice, how do I take the spaces out of the print function?
class Board(object):
"""board of pieces"""
def __init__(self):
self.board = [['0']*7]*6 #6x7 grid
self.board[3][6] = 8
def printBoard(self):
"""Display the board array"""
print self.board
for i in range(6):
for j in range(7):
print self.board[i][j],
print "\n",
0 0 0 0 0 0 8
0 0 0 0 0 0 8
0 0 0 0 0 0 8
0 0 0 0 0 0 8
0 0 0 0 0 0 8
0 0 0 0 0 0 8
You need to rewrite self.board as follows
self.board = [['0']*7 for i in range(6)]
Read about creating multidimentional lists in Python FAQ.
Here is an excerpt from the answer in the FAQ.
The reason is that replicating a list with * doesn’t create copies, it
only creates references to the existing objects. The *3 creates a list
containing 3 references to the same list of length two. Changes to one
row will show in all rows, which is almost certainly not what you
want.
class Board(object):
"""board of pieces"""
def __init__(self):
self.board = [['0']*7 for i in range(6)] #6x7 grid
self.board[3][6] = '8'
def printBoard(self):
"""Display the board array"""
print self.board
for i in range(6):
print ''.join(self.board[i])
Maybe this is a duplicated question and this is the best answer i found there: (I adapted the example)
You can use list comprehensions
[x[:] for x in [['0']*7]*6]
[['0']*7]*6 creates a list of the same object repeated 6 times. You
can't just use this, because modifying one element will modify that
same element in each row!
x[:] is equivalent to list(X) but is a bit more efficient since it
avoids the name lookup. Either way, it creates a shallow copy of each
row, so now all the elements are independent.
I prefer to use a dictionary indexed by tuples for multidimensional arrays:
class Board(object):
"""board of pieces"""
WIDTH = 7
HEIGHT = 6
def __init__(self):
self.board = {}
for i in range(self.HEIGHT):
for j in range(self.WIDTH):
self.board[i,j] = 0
self.board[3,6] = 8
def printBoard(self):
"""Display the board array"""
print self.board
for i in range(6):
for j in range(7):
print self.board[i,j],
print "\n",

Categories

Resources