Breadth's Algorithm Runs Forever Despite Possible Ending - python

So I saw this coding interview question and tried to solve it. I am trying to employ Breadth's Path Finding Algorithm to find the optimum flight routes from a given airport to all other airports; given the list of all airports and routes. An element in routes means that there is a one way flight from the first airport to the second one.
I got here, this was supposed to find the shortest routes to all other airports from a given airport. But when I run it never ends.
I figured that my algorithm doesn't append all possible next airports to my paths, but everything seems o.k to me.
'''
import queue
airports = ["BGI", "CDG", "DEL", "DOH", "DSM", "EWR", "EYW", "HND", "ICN", "JFK", "LGA",
"LHR", "ORD", "SAN", "SFO", "SIN", "TLV", "BUD"]
routes = [["DSM", "ORD"], ["ORD", "BGI"], ["BGI", "LGA"], ["SIN", "CDG"], ["CDG", "SIN"],
["CDG", "BUD"], ["DEL", "DOH"], ["DEL", "CDG"], ["TLV", "DEL"], ["EWR", "HND"],
["HND", "ICN"], ["HND", "JFK"], ["ICN", "JFK"], ["JFK", "LGA"], ["EYW", "LHR"],
["LHR", "SFO"], ["SFO", "SAN"], ["SFO", "DSM"], ["SAN", "EYW"], ["LGA", "EYW"]]
main = "LGA"
def done(moves, aim):
if moves == "":
return False
elif moves[-1][1] == aim:
return True
return False
def valid(moves, put):
if moves == "":
return False
if moves[-1][1] == put[0]:
return True
return False
def available_starts(start, pos):
anfaenge = list()
for i in pos:
if i[0] == start:
anfaenge.append(i)
return anfaenge
#MAIN ALGORITHM
kurzeste_moeglichkeiten = [] """all shortest possibilities"""
for port in airports:
nums = queue.Queue()
nums.put("")
add = ""
start = main
if port != start:
anfaenge = available_starts(start, routes) """possible startings"""
for anfang in anfaenge:
anfang = [anfang]
nums.put(anfang)
while not done(add, port):
add = nums.get()
for got in routes:
if valid(add, got):
t = add
t.append(got)
nums.put(t)
kurzeste_moeglichkeiten.append(add)
for eine in kurzeste_moeglichkeiten:
print(eine)
'''

I've managed to represent your graph with the modules networkx and matplotlib. As you can see, the airports are splitted in 2 groups.
As mentionned, I do believe 2 of your routes ["SIN", "CDG"] and ["CDG", "SIN"] are the reverse ones and are not OK with the rest of your data.
NOTE: the code I've used to show the graph:
import networkx as nx
import matplotlib.pyplot as plt
airports = ["BGI", "CDG", "DEL", "DOH", "DSM", "EWR", "EYW", "HND", "ICN", "JFK", "LGA",
"LHR", "ORD", "SAN", "SFO", "SIN", "TLV", "BUD"]
legs = [["DSM", "ORD"], ["ORD", "BGI"], ["BGI", "LGA"], ["SIN", "CDG"], ["CDG", "SIN"],
["CDG", "BUD"], ["DEL", "DOH"], ["DEL", "CDG"], ["TLV", "DEL"], ["EWR", "HND"],
["HND", "ICN"], ["HND", "JFK"], ["ICN", "JFK"], ["JFK", "LGA"], ["EYW", "LHR"],
["LHR", "SFO"], ["SFO", "SAN"], ["SFO", "DSM"], ["SAN", "EYW"], ["LGA", "EYW"]]
main = "LGA"
G = nx.Graph()
for node in airports:
G.add_node(node)
for leg in legs:
G.add_edge(leg[0], leg[1])
plt.subplot(121)
nx.draw(G, with_labels=True)

Related

Color of node wont change in Pyvis

I am trying to build a networkx digraph of blockchain transaction data and visualize it using Pyvis. I believe that I have the graph working, but I want to change the color of the transactions that involve Uniswap. I am having trouble doing that though as the colors never change. Here is my code:
G = nx.DiGraph()
# Read data in from csv and seperate data
data = pd.read_csv('apecoin_trans_data_1day_072822.csv')
fro = data['address_from']
to = data['address_to']
date_time = data['date_time']
amount = data['amount']
edges_data = zip(fro, to, date_time, amount)
transaction = []
# Create the graph
for e in edges_data:
src = e[0]
tar = e[1]
G.add_node(src)
G.add_node(tar)
transaction.append((src, tar))
G.add_edges_from(transaction)
net = Network(height='750px', width='100%', notebook=False, directed=True)
net.from_nx(G)
# Get adjacency list for graph
neighbor_map = net.get_adj_list()
for node in net.nodes:
node["value"] = len(neighbor_map[node["id"]])
if node["id"] == "\xac4b3dacb91461209ae9d41ec517c2b9cb1b7daf":
node["color"] = "red"
else:
node["color"] = "blue"
net.show("networkmap.html")
The data is formatted like so:
address_from,address_to,date_time,amount
\xdbb69ea87507525fffbd1c4f1ad6f7d30a9a402e,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-27T23:02:04+00:00,93.4673619317370716
\xba12222222228d8ba445958a75a0704d566bf2c8,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-27T23:02:30+00:00,95.7735945510702722
\xf784470541ad1f94902c387514756c7d831e20a7,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-28T00:06:38+00:00,8422.2499709617088153
\xf784470541ad1f94902c387514756c7d831e20a7,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-28T00:08:08+00:00,1337.1683051620927162
\x6eb0ed09ac237f4c607a18b8dc63b48efe61b9b8,\x00000000009726632680fb29d3f7a9734e3010e2,2022-07-28T13:57:26+00:00,1000.0000000000000000
I ended up figuring it out. I was doing the following:
if node["id"] == "\xac4b3dacb91461209ae9d41ec517c2b9cb1b7daf"
When it should have been this:
if node["id"] == r'\xac4b3dacb91461209ae9d41ec517c2b9cb1b7daf'

How to keep locator at the centre of parents when deleting parent constraint in python

import maya.cmds as cmds
sel = cmds.ls(sl = True)
cmds.spaceLocator(n = 'driver')
for i in sel:
cmds.parentConstraint(i, 'driver', n = 'delPs', mo = False)
#until this line, the 'driver' keeps its position at the centre of i
cmds.delete('delPs')
#after this line, the 'driver' moves to the pivot point of the last item on the selection.
I'm trying to keep locator(driver) at the centre of the selected objects after delete constraint node.Can I get some advise?
im not sure to understand your problem but here is some solutions, hope one will help you, im using math instead of constraint
from __future__ import division
import maya.cmds as cmds
# =========================
#just to illustrate an exemple selection of 10 sphere combined
import random
psph = [cmds.polySphere()[0] for i in range(4)]
for i in psph:
cmds.setAttr(i+'.t', random.uniform(0.0, 10), random.uniform(0.0, 10), random.uniform(0.0, 10))
# sph_comb = cmds.polyUnite(psph)
cmds.delete(psph , ch=True)
# ===============================
def getCentroid(sel):
obj = cmds.ls(sel, o=True)
sel = cmds.polyListComponentConversion(sel, tv=True)
sel = cmds.ls(sel, flatten=1)
if len(obj) > 1:
pos = []
for s in sel:
p = cmds.xform(s, q=1, t=1, ws=1)
pos += p
else:
pos = cmds.xform(sel, q=1, t=1, ws=1)
nb = len(sel)
myCenter = sum(pos[0::3]) / nb, sum(pos[1::3]) / nb, sum(pos[2::3]) / nb
return myCenter
# example for each sphere
sel= cmds.ls(psph)
for i in sel:
loc = cmds.spaceLocator(n = 'driver')[0]
coord = getCentroid(i)
cmds.setAttr(loc+'.t', *coord)
# for only one at the center of all sphres
sel= cmds.ls(psph)
coord = getCentroid(sel)
loc = cmds.spaceLocator()[0]
cmds.setAttr(loc+'.t', *coord)
EDIT : fix some code issue on my function getCentroid because xform can get multiple object

Implementing Bellman-Ford in python

I'm trying to adapt a Bellman-Ford graph algorithm in Python to my needs.
I've worked out the parsing part from a json file.
Here is the Bellman Ford code I found on github:
https://github.com/rosshochwert/arbitrage/blob/master/arbitrage.py
And here is my code I adapted from it:
import math, urllib2, json, re
def download():
graph = {}
page = urllib2.urlopen("https://bittrex.com/api/v1.1/public/getmarketsummaries")
jsrates = json.loads(page.read())
result_list = jsrates["result"]
for result_index, result in enumerate(result_list):
ask = result["Ask"]
market = result["MarketName"]
pattern = re.compile("([A-Z0-9]*)-([A-Z0-9]*)")
matches = pattern.match(market)
if (float(ask != 0)):
conversion_rate = -math.log(float(ask))
if matches:
from_rate = matches.group(1).encode('ascii','ignore')
to_rate = matches.group(2).encode('ascii','ignore')
if from_rate != to_rate:
if from_rate not in graph:
graph[from_rate] = {}
graph[from_rate][to_rate] = float(conversion_rate)
return graph
# Step 1: For each node prepare the destination and predecessor
def initialize(graph, source):
d = {} # Stands for destination
p = {} # Stands for predecessor
for node in graph:
d[node] = float('Inf') # We start admiting that the rest of nodes are very very far
p[node] = None
d[source] = 0 # For the source we know how to reach
return d, p
def relax(node, neighbour, graph, d, p):
# If the distance between the node and the neighbour is lower than the one I have now
if d[neighbour] > d[node] + graph[node][neighbour]:
# Record this lower distance
d[neighbour] = d[node] + graph[node][neighbour]
p[neighbour] = node
def retrace_negative_loop(p, start):
arbitrageLoop = [start]
next_node = start
while True:
next_node = p[next_node]
if next_node not in arbitrageLoop:
arbitrageLoop.append(next_node)
else:
arbitrageLoop.append(next_node)
arbitrageLoop = arbitrageLoop[arbitrageLoop.index(next_node):]
return arbitrageLoop
def bellman_ford(graph, source):
d, p = initialize(graph, source)
for i in range(len(graph)-1): #Run this until is converges
for u in graph:
for v in graph[u]: #For each neighbour of u
relax(u, v, graph, d, p) #Lets relax it
# Step 3: check for negative-weight cycles
for u in graph:
for v in graph[u]:
if d[v] < d[u] + graph[u][v]:
return(retrace_negative_loop(p, source))
return None
paths = []
graph = download()
print graph
for ask in graph:
path = bellman_ford(graph, ask)
if path not in paths and not None:
paths.append(path)
for path in paths:
if path == None:
print("No opportunity here :(")
else:
money = 100
print "Starting with %(money)i in %(currency)s" % {"money":money,"currency":path[0]}
for i,value in enumerate(path):
if i+1 < len(path):
start = path[i]
end = path[i+1]
rate = math.exp(-graph[start][end])
money *= rate
print "%(start)s to %(end)s at %(rate)f = %(money)f" % {"start":start,"end":end,"rate":rate,"money":money}
print "\n"
Error:
Traceback (most recent call last):
File "belltestbit.py", line 78, in <module>
path = bellman_ford(graph, ask)
File "belltestbit.py", line 61, in bellman_ford
relax(u, v, graph, d, p) #Lets relax it
File "belltestbit.py", line 38, in relax
if d[neighbour] > d[node] + graph[node][neighbour]:
KeyError: 'LTC'
When I print the graph I got everything needed. It is 'LTC' because it is the first one the list. I tried executing and filtering LTC, it gives me the same error with the first name coming on the graph:
Traceback (most recent call last):
File "belltestbit.py", line 78, in <module>
path = bellman_ford(graph, ask)
File "belltestbit.py", line 61, in bellman_ford
relax(u, v, graph, d, p) #Lets relax it
File "belltestbit.py", line 38, in relax
if d[neighbour] > d[node] + graph[node][neighbour]:
KeyError: 'NEO'
I don't see how could I fix this.
Thanks everyone.
PS: It appears that an answer was deleted, I'm new to SO, so I don't know what happened. I edited the post, because the answer helped me to advance :)
Disclaimer: Note that although you can find "inefficiencies" in this way, the chances you could actually use them to earn money are quite low. Most probably you would actually loose some money. AFAICS from the data I've seen during testing, those "inefficiencies" come from the fact that exchange rates are more volatile over course of minutes than the Bid-Ask spread. So what you see as an inefficiency is probably just a stale data and you can't actually execute all the required orders fast enough for the exchange rate to be stable enough to earn money. So be advised that you might loose your money if you try to use this application for anything more than your curiosity.
So now to the business:
Your data is in a different format than the one that the original code was designed for. Typical piece of data looks like this:
{
"MarketName": "BTC-ETH",
"High": 0.05076884,
"Low": 0.04818392,
"Volume": 77969.61816991,
"Last": 0.04978511,
"BaseVolume": 3875.47491925,
"TimeStamp": "2017-12-29T05:45:10.18",
"Bid": 0.04978511,
"Ask": 0.04986673,
"OpenBuyOrders": 4805,
"OpenSellOrders": 8184,
"PrevDay": 0.04955001,
"Created": "2015-08-14T09:02:24.817"
}
What you are interested in is MarketName, Bid and Ask. And you need to understand what those Bid and Ask mean. Roughly speaking the Ask value means that if you want to sell BTC for ETH there is (or rather was not too long ago) a buyer who is willing to buy your BTC using exchange rate 0.04986673 BTC for 1 ETH. Similarly the Bid value means that if you want to sell ETH for BTC there is (was) a buyer who is willing to buy your ETH using exchange rate 0.04978511 BTC for 1 ETH. Note that this structure means that you will not have a record with "MarketName": "ETH-BTC" because it provides no additional data.
So knowing that you can fill your graph with proper distances, which are logarithms of the corresponding rates. Also I believe that there is another bug in your code: since the argument p of the retrace_negative_loop is actually dictionary of predecessor nodes, retrace_negative_loop returns the negative loop in the reverse order. And since your graph is directed the same loop might be positive in one direction and negative in the other one.
import math, urllib2, json, re
def download():
graph = {}
page = urllib2.urlopen("https://bittrex.com/api/v1.1/public/getmarketsummaries")
data = page.read()
jsrates = json.loads(data)
result_list = jsrates["result"]
for result_index, result in enumerate(result_list):
ask = result["Ask"]
bid = result["Bid"]
market = result["MarketName"]
pattern = re.compile("([A-Z0-9]*)-([A-Z0-9]*)")
matches = pattern.match(market)
if matches:
from_rate = matches.group(1).encode('ascii', 'ignore')
to_rate = matches.group(2).encode('ascii', 'ignore')
# different sign of log is effectively 1/x
if ask != 0:
if from_rate not in graph:
graph[from_rate] = {}
graph[from_rate][to_rate] = math.log(float(ask))
if bid != 0:
if to_rate not in graph:
graph[to_rate] = {}
graph[to_rate][from_rate] = -math.log(float(bid))
return graph # Step 1: For each node prepare the destination and predecessor
def initialize(graph, source):
d = {} # Stands for destination
p = {} # Stands for predecessor
for node in graph:
d[node] = float('Inf') # We start admiting that the rest of nodes are very very far
p[node] = None
d[source] = 0 # For the source we know how to reach
return d, p
def relax(node, neighbour, graph, d, p):
# If the distance between the node and the neighbour is lower than the one I have now
dist = graph[node][neighbour]
if d[neighbour] > d[node] + dist:
# Record this lower distance
d[neighbour] = d[node] + dist
p[neighbour] = node
def retrace_negative_loop(p, start):
arbitrageLoop = [start]
prev_node = start
while True:
prev_node = p[prev_node]
if prev_node not in arbitrageLoop:
arbitrageLoop.append(prev_node)
else:
arbitrageLoop.append(prev_node)
arbitrageLoop = arbitrageLoop[arbitrageLoop.index(prev_node):]
# return arbitrageLoop
return list(reversed(arbitrageLoop))
def bellman_ford(graph, source):
d, p = initialize(graph, source)
for i in range(len(graph) - 1): # Run this until is converges
for u in graph:
for v in graph[u]: # For each neighbour of u
relax(u, v, graph, d, p) # Lets relax it
# Step 3: check for negative-weight cycles
for u in graph:
for v in graph[u]:
if d[v] < d[u] + graph[u][v]:
return retrace_negative_loop(p, v)
return None
graph = download()
# print graph
for k, v in graph.iteritems():
print "{0} => {1}".format(k, v)
print "-------------------------------"
paths = []
for currency in graph:
path = bellman_ford(graph, currency)
if path not in paths and not None:
paths.append(path)
for path in paths:
if path == None:
print("No opportunity here :(")
else:
money = 100
print "Starting with %(money)i in %(currency)s" % {"money": money, "currency": path[0]}
for i, value in enumerate(path):
if i + 1 < len(path):
start = path[i]
end = path[i + 1]
rate = math.exp(-graph[start][end])
money *= rate
print "%(start)s to %(end)s at %(rate)f = %(money)f" % {"start": start, "end": end, "rate": rate,
"money": money}
print "\n"
Also the check if path not in paths and not None: is potentially not enough because it doesn't filter our paths that are just rotations of one another but I didn't bother with fixing that as well.

Function returning same values for supposedly different inputs

I'm using pyalgotrade to create a trading strategy. I'm going through a list of tickers(testlist) and adding them to a dictionary(list_large{}) alongside their score which I'm getting using a get_score function. My latest problem is that each ticker in the dictionary(list_large{}) is getting the same score. Any idea why?
Code:
from pyalgotrade import strategy
from pyalgotrade.tools import yahoofinance
import numpy as np
import pandas as pd
from collections import OrderedDict
from pyalgotrade.technical import ma
from talib import MA_Type
import talib
smaPeriod = 10
testlist = ['aapl','ddd','gg','z']
class MyStrategy(strategy.BacktestingStrategy):
def __init__(self, feed, instrument):
super(MyStrategy, self).__init__(feed, 1000)
self.__position = []
self.__instrument = instrument
self.setUseAdjustedValues(True)
self.__prices = feed[instrument].getPriceDataSeries()
self.__sma = ma.SMA(feed[instrument].getPriceDataSeries(), smaPeriod)
def get_score(self,slope):
MA_Score = self.__sma[-1] * slope
return MA_Score
def onBars(self, bars):
global bar
bar = bars[self.__instrument]
slope = 8
for instrument in bars.getInstruments():
list_large = {}
for tickers in testlist: #replace with real list when ready
list_large.update({tickers : self.get_score(slope)})
organized_list = OrderedDict(sorted(list_large.items(), key=lambda t: -t[1]))#organize the list from highest to lowest score
print list_large
def run_strategy(inst):
# Load the yahoo feed from the CSV file
feed = yahoofinance.build_feed([inst],2015,2016, ".") # feed = yahoofinance.build_feed([inst],2015,2016, ".")
# Evaluate the strategy with the feed.
myStrategy = MyStrategy(feed, inst)
myStrategy.run()
print "Final portfolio value: $%.2f" % myStrategy.getBroker().getEquity()
def main():
instruments = ['ddd','msft']
for inst in instruments:
run_strategy(inst)
if __name__ == '__main__':
main()
Check this code of the onBars() function:
slope = 8 # <---- value of slope = 8
for instrument in bars.getInstruments():
list_large = {}
for tickers in testlist: #replace with real list when ready
list_large.update({tickers : self.get_score(slope)})
# Updating dict of each ticker based on ^
Each time self.get_score(slope) is called, it returns the same value and hence, all the value of tickers hold the same value in dict
I do not know how you want to deal with slope and how you want to update it's value. But this logic can be simplified without using .update as:
list_large = {}
for tickers in testlist:
list_large[tickers] = self.get_score(slope)
# ^ Update value of `tickers` key

Appending variables from previous method calls in later ones

Hi a sample output from running this code is shown as well, The script runs as well, you could run it to get a sense of what it does. My problem, is given the three different calls to the route() function what codes can I add to get a list of all previous objective function values ie obj variable on line 79.
desired output = obj_rslt = [20.989285714285714, 21.166176470588233, 25.8656 ]
I have tried to use the copy.copy() but it does not work, I need a list of all values as shown above for further work in another function. Thank you.
#import statements
import copy
import networkx as nx
import random as rand
#Define nodes and Edges
pos = {1001:(-42503,-3748871),1002:(-42267,-3749806),1003:(-40938,-3750235),1004: (-39452,-3750624),1005:(-39985,-3749564),1006:(-38473,-3749615),1007:(-41714,-3747171),1008:(-42279,-3745275),1009:(-41853,-3744185),1010:(-42000,-3746561),1011:(-42651,-3746188),1012:(-42195,-3747788),1013:(-41498,-3748890),1014:(-40366,-3748684),1015:(-43036,-3750284)}
edge = [(1001, 1003,{'length':0.35}),(1001, 1004,{'length':0.46}),(1001, 1009,{'length':0.49}),(1002, 1007,{'length':0.22}),(1002, 9972,{'length':0.54}),(1002, 1013,{'length':0.59}),(1003, 1014,{'length':0.25}),(1004, 1010,{'length':0.29}),(1004, 1013,{'length':0.57}),(1004, 1003,{'length':0.43}),(1004, 1006,{'length':0.37}),(1005, 1002,{'length':0.23}),(1005, 14566,{'length':0.72}),(1006, 1005,{'length':0.6}),(1007, 1003,{'length':0.39}),(1007, 1010,{'length':0.11}),(1009, 1001,{'length':0.51}),(1010, 1005,{'length':0.2}),(1011, 1004,{'length':0.37}),(1012, 1006,{'length':0.17}),(1013, 1005,{'length':0.19}),(1013, 1007,{'length':0.21}),(1014, 1005,{'length':0.35}),(1014, 1009,{'length':0.51})]
#Create the graph and add the nodes and edges
X = nx.MultiDiGraph()
X.add_nodes_from(pos.keys())
X.add_edges_from(edge)
def routes():
""" This function cretaes busroutes """
individual = []
shortest_path_length = []
num_routes = 3
#Generate the bus routes
for i in xrange(num_routes):
while True:
try:
A = int(rand.choice(pos.keys()))
B = int(rand.choice(pos.keys()))
path = nx.dijkstra_path(X,A,B,weight='length')
individual.append(path)
pathlength = round(nx.dijkstra_path_length(X,A,B),2)
if pathlength > 1:
shortest_path_length.append(pathlength)
break
else: pathlength
except:pass
# Loop through the list of shortest path nodes to get the nodes for the bus route
#bus_route_nodes = [map(lambda x: str(x) + '.0', l) for l in individual]
veh_spid = []
veh_hdw = []
obj_rslt = []
for ind in individual:
try:
headway = rand.randint(2, 30)
veh_hdw.append(headway)
speed = rand.choice([2,15,66])
veh_spid.append(speed)
except: pass
# Print bus route features
print 'OUTPUTS:'
print 'Route Name:', str(ind[0]) + ' ' + '-' + ' ' + str(ind[-1])
print 'Route Number:', individual.index(ind) + 1
print 'Route headway = ',headway
print 'Route speed = ',speed
print 'shortest path length', shortest_path_length
# Average network characteristics gotten by taken the mean of individual characteristics that make up each network
ntwk_len = sum(shortest_path_length)
ntwk_spid = sum(veh_spid)/len(veh_spid)
ntwk_hdwy = sum(veh_hdw )/len(veh_hdw)
#Calculate objective function values
obj = [0]
obj = copy.copy(obj)
obj = ( (ntwk_len/ntwk_spid) + 5 * (60/ntwk_hdwy) + (ntwk_len) )
obj_rslt.append(obj)
print 'obj_rslt', obj_rslt
print
return individual
#Three distinct method calls
routes()
routes()
routes()
OUTPUTS:
Route Name: 1014 - 1001
Route Number: 6
Route headway = 29
Route speed = 2
shortest path length [1.8, 2.77, 1.02]
obj_rslt [20.989285714285714]
OUTPUTS:
Route Name: 1003 - 1007
Route Number: 9
Route headway = 5
Route speed = 66
shortest path length [2.37, 2.57, 1.05]
obj_rslt [21.166176470588233]
OUTPUTS:
Route Name: 1012 - 1013
Route Number: 6
Route headway = 6
Route speed = 66
shortest path length [2.2, 1.85, 1.59]
obj_rslt [25.8656]
desired output = obj_rslt = [20.989285714285714, 21.166176470588233, 25.8656 ]
The problem is that you always set obj_rslt to []
Move the assignment obj_rslt = [] out of the method after the definition of pos and edge then you should be fine
#...your code
obj_results = []
def routes():
#do some computation and assume you store it in
#a variable called res
obj_results.append(res)
return res
routes()
routes()
routes()
print obj_results
The ouput will be a list with all three results

Categories