I come from C background currently learning Python. My task is to create a general tree. The input to the program is in two passes. In the first pass I must collect the identity, name, role and dept of a person. In the second pass I get to know the parent of a node, the manager. So I must store the values transiently. In C I would typically use an array of structs or a linked list depending on the availability of the size information. But I am lost here in Python, not even sure if what I am doing is okay let alone efficient.
Thanks in advance,
Preeti.
if __name__ == "__main__":
# Have successfully created the tree and added nodes by hardcoding values as shown below in commented code
# create_tree = Tree()
# Tree.add_node(42, "Stephen", "Time Cone Radiation", "Black Hole")
# But unable to figure out how to store transient info and use it later to create the tree.
num = 8
list = []
backup_num = num
while num:
id, name, role, dept = raw_input().split()
num -= 1
list.append((id, name, role, dept))
while backup_num:
id, parent = raw_input().split()
backup_num -= 1
#For an id in the list above locate it, and call add_node.
# But not sure how and what is an efficient way.
This will give you a fare idea. Hope this helps.
class Tree():
def __init__(self):
self.length = 0
self.data = {}
def add_node(self, nodeid, name, role, dept):
obj = {}
obj["child"] = {"left": None, "right": None}
obj["parent_id"] = None
obj["name"] = name
obj["role"] = role
obj["dept"] = dept
self.data[nodeid] = obj
self.length += 1
return True
# which_one : Left or Right
def update_child_id(self, which_one, nodeid_parent, nodeid_child):
self.data[nodeid_parent]["child"][which_one] = nodeid_child
return True
def update_parent(self, nodeid, parent_id):
self.data[nodeid]["parent_id"] = parent_id
return True
def display_node(self, nodeid):
obj = self.data[nodeid]
print("Node:", nodeid)
print("Parent:", obj["parent_id"], ", Name:", obj["name"], ", Role: ", obj["role"], ", Dept: ", obj["dept"])
def display_child(self, nodeid):
print(self.data[nodeid]["child"].items())
# Main
test = Tree()
# Get the identity and then add here
node_id, name, role, dept = [42, "Stephen", "Time Cone Radiation", "Black Hole"]
test.add_node(node_id, name, role, dept)
# Get the parent id and add here
parent_id, parent = [6, "James"]
test.update_parent(node_id, parent_id)
test.display_node(42)
test.display_child(42)
Related
I am trying to create a Python program which has the details of power grids and the houses connected to each of those power grids.
I have mainly two tasks to handle, one to add houses to the connection list of each power grid and remove them.
Following is the class for my house:
class House:
def __init__(self, number, power):
self.house_no = number
self.power_required = power
self.assigned_propagator_no = -1
def assign_propagtor(self, number):
self.assigned_propagator_no = number
def __str__(self):
return f"house_no: {self.house_no} power_required: {self.power_required}"
I have a propagator class which is basically used to store all the details and connect between the houses and the power grids:
class Propagator:
def __init__(self, number, max_power):
self.propagator_no = number
self.maximum_power = max_power
self.power_remaining = max_power
self.houses_connected = list()
def __str__(self):
return f"no : {self.propagator_no} max_power: {self.maximum_power} power_remaining: {self.power_remaining}"
def connected_houses_info(self):
for house,_ in self.houses_connected:
print(house)
# check if the house is connected part of the list or not.
def is_house_present(self, house_no):
if house_no in self.houses_connected:
return self.houses_connected.index(house_no)
else:
return -1
# Add the house in the list.
# Before adding check if the house is already connected
def add_house(self, house:House):
if house.assigned_propagator_no != -1:
print('Already exists!')
else:
self.houses_connected.append(house.house_no)
# Remove the house from the list, before removing need to check
# if the house is in the assigned propoagtor list.
def remove_house(self, house_no:int):
pass
Similarly I have created the class for my power grid:
class PowerGrid:
def __init__(self):
self.propagators = dict()
# Adding the propagtor into in the dictionary.
# Check if the propagator is not part of the dictioary already
# It will not posess any value in the beginning.
def add_propagator(self, propagator:Propagator):
pass
# Removing the propagtor into in the dictionary.
# Check if the propagator is part of the dictioary or not
def remove_propagator(self, propagator_no):
pass
def add_house(self, house:House, propagator_no:int):
if propagator_no in self.propagators:
return self.propagators[propagator_no].add_house(house)
else:
return False
def remove_house(self, house_no:int, propagator_no:int):
if propagator_no in self.propagators:
return self.propagators[propagator_no].remove_house(house_no)
else:
return False
class Propagator:
def __init__(self, number, max_power):
self.propagator_no = number
self.maximum_power = max_power
self.power_remaining = max_power
self.houses_connected = list()
def __str__(self):
return f"no : {self.propagator_no} max_power: {self.maximum_power} power_remaining: {self.power_remaining}"
def connected_houses_info(self):
for house,_ in self.houses_connected:
print(house)
# check if the house is connected part of the list or not.
def is_house_present(self, house_no):
if house_no in self.houses_connected:
return self.houses_connected.index(house_no)
else:
return -1
# Add the house in the list.
# Before adding check if the house is already connected
def add_house(self, house:House):
pass
# Remove the house from the list, before removing need to check
# if the house is in the assigned propoagtor list.
def remove_house(self, house_no:int):
pass
The main function to create the power grid is as follows:
def create_power_grid():
power_grid = PowerGrid()
with open('app.csv', newline='') as csvfile: # app.csv image provided later
reader = csv.DictReader(csvfile)
for row in reader:
entity_type = row['Type']
if entity_type == "propagator":
propagator = Propagator(int(row['Entity_Number']), int(row['Power']))
power_grid.add_propagator(propagator)
elif entity_type == "house":
house = House(int(row['Entity_Number']), int(row['Power']))
house.assigned_propagator_no = int(row['Assigned_Propagator'])
power_grid.add_house(house, int(row['Assigned_Propagator']))
return power_grid
if __name__ == "__main__":
power_grid = create_power_grid()
for _, propagator in power_grid.propagators.items():
#Printing the propagator information
print(f"Propagator No : {propagator.propagator_no}")
print("------------Propagator Information-----------------")
print(propagator)
print("------------Connected Houses Information-----------------")
propagator.connected_houses_info()
print("\n")
print("----Removing House 1014 from Propagator 1002----")
if power_grid.remove_house(1014, 1002):
print("House 1014 is successfully removed from Propagator 1002")
else:
print("House 1014 is not connected with Propagator 1002")
print("\n----Removing House 1024 from Propagator 1003----")
if power_grid.remove_house(1024, 1003):
print("House 1024 is successfully removed from Propagator 1003")
else:
print("House 1024 is not connected with Propagator 1003")
I have made certain changes to the add_propagator function inside class PowerGrid as follows:
def add_propagator(self, propagator:Propagator):
if (propagator.propagator_no not in self.propagators.keys()):
self.propagators[propagator.propagator_no] = {}
self.propagators[propagator.propagator_no]['max_power'] = propagator.maximum_power
self.propagators[propagator.propagator_no]['houses'] = []
But I am getting an error:
AttributeError: 'dict' object has no attribute 'add_house'
for the following part:
def add_house(self, house:House, propagator_no:int):
if propagator_no in self.propagators:
return self.propagators[propagator_no].add_house(house)
else:
return False
I have a CSV file from which the values are fed in. The format of the CSV file looks like the following:
I am unable to understand how to define the addition of a house and removal of a house from this, any kind of help with explanation is appreciated.
To have a key correspond to a list in a dictionary in python, note that d[item] is a list::
d = dict()
for item in items_to_add:
if item not in d:
d[item] = []
d[item].append(the_other_item)
# in your case:
if propagator_no not in self.propagators:
self.propagators[propagator_no] = []
self.propagators[propagator_no].append(house)
Your problem is that self.propogators is a dictionary, and therefore has these functions, not add_house.
I have a python problem that creates a box and puts items in the box and with the help of the list command I can see what's in my box. One example of the execution may go as:
next command> newbox bedroom-box-05
next command> add bedroom-box-05 pillow 3
next command> list bedroom-box-05
Box "bedroom-box-05" contains 3 items.
3 pillow
There are some issues with class MovingBox() as I cannot change the main functions.
class MovingBox():
"""A class for keeping track of the contents ofa moving box. """
def __init__(self,*args):
self = dict()
def add_item(self,key,value =[]):
setattr(self,key,value)
self.add_item=value
def list_content(self,key,value =[]):
setattr(self, key, value)
self.list_content = value
key1 = Keys() # parens
key1.list_content(value)
DON'T CHANGE ANYTHING AFTER THIS LINE
def convert_str_to_int(word):
"""
Converts the parameter string *word* in to an integer value.
"""
try:
result = int(word)
except ValueError:
return None
return result
def newbox(all_boxes, list_of_additional_info):
if len(list_of_additional_info) != 1:
print("Error: wrong number of initial data: can't create a new box.")
return
box_name = list_of_additional_info[0]
all_boxes[box_name] = MovingBox(box_name)
def add_to_box(all_boxes, list_of_additional_info):
if len(list_of_additional_info) != 3:
print("Error: wrong number of elements: can't add into a box.")
return
box_name, item_name, item_count = list_of_additional_info
item_count = convert_str_to_int(item_count)
if item_count is None:
print("Error: not a number: can't add to a box.")
return
if box_name not in all_boxes:
print("Error: box does not exist: can't add to a box.")
return
all_boxes[box_name].add_item(item_name, item_count)
def list_box_content(all_boxes, list_of_additional_info):
"""Displays the contents of a single box in *all_boxes* """
if len(list_of_additional_info) != 1:
print("Error: wrong number of elements: can't list contents.")
return
box_name = list_of_additional_info[0]
if box_name not in all_boxes:
print("Error: box does not exist: can't list content.")
return
all_boxes[box_name].list_content()
def main():
boxes = {}
while True:
command_line = input("next command> ").strip()
if command_line == "":
break
command_words = command_line.split()
first_word = command_words[0]
list_of_other_words = command_words[1:]
if first_word == "quit":
break
elif first_word == "newbox":
newbox(boxes, list_of_other_words)
elif first_word == "add":
add_to_box(boxes, list_of_other_words)
elif first_word == "list":
list_box_content(boxes, list_of_other_words)
if __name__ == "__main__":
main()
Based on the way this class is being used in the code that you're not supposed to change, I don't think you've understood what the MovingBox is supposed to contain/model. Here are examples of how MovingBox is being used:
MovingBox(box_name)
# creates a box named box_name
all_boxes[box_name].add_item(item_name, item_count)
# increments the count of item_name by item_count
all_boxes[box_name].list_content()
# lists the content of the box
The immediate error you're hitting is that list_content isn't supposed to take a parameter, but the larger problem is that what you've tried to implement doesn't match up at all with what the rest of the code is trying to do -- e.g. your implementation of add_item seems to be trying to add a unique item with an arbitrary value (that defaults to [], which has its own problems), when the calling code is actually providing a count of a type of item.
Since MovingBox is seemingly supposed to just be a counter with a custom interface, I'd implement it as a wrapper around collections.Counter:
from collections import Counter
class MovingBox():
"""A class for keeping track of the contents of a moving box. """
def __init__(self, name: str):
self.name = name
self.contents = Counter()
def add_item(self, name: str, count: int) -> None:
self.contents[name] += count
def list_content(self) -> None:
total = sum(self.contents.values())
print(f'Box "{self.name}" contains {total} items.')
for name, count in self.contents.items():
print(f'{count} {name}')
>>> box = MovingBox("a box")
>>> box.add_item("pillow", 3)
>>> box.list_content()
Box "a box" contains 3 items.
3 pillow
Let's consider this example in Python 3:
class SimpleObj:
def __init__(self, own_id: int, parent_id: int):
self.parent_id = parent_id
self.own_id = own_id
self.children_objects = [] # type: List[SimpleObj]
test_dict = {}
test_dict[0] = SimpleObj(own_id=0, parent_id=-1) # -1 will mean root node
test_dict[1] = SimpleObj(own_id=1, parent_id=0)
test_dict[123] = SimpleObj(own_id=123, parent_id=1)
test_dict[5] = SimpleObj(own_id=5, parent_id=123)
What would be the most pythonic way to create a recursive, nested structure where for example SimpleObj with own_id=1 would have its children_objects list filled with one element which would be SimpleObj with own_id=123?
It smells so similar to binary tree problem but I really didn't manage to find a working solution to turn this kind of dictionary into a tree-like objects' structure.
May be you can create a small function to handle the creation of a new SimpleObj :
class SimpleObj:
def __init__(self, own_id: int, parent_id: int):
self.parent_id = parent_id
self.own_id = own_id
self.children_objects = []
def addSimpleObj(struct, own_id, parent_id):
struct[own_id] = SimpleObj(own_id=own_id, parent_id=parent_id)
if parent_id != -1:
try:
struct[parent_id].children_objects.append(struct[own_id])
except IndexError:
print('the parent_id does not exists')
test_dict = {}
addSimpleObj(test_dict, 0, -1)
addSimpleObj(test_dict, 1, 0)
addSimpleObj(test_dict, 123, 1)
addSimpleObj(test_dict, 5, 123)
It's just a start but it seems to do the trick. You could modify it to handle, for example, the case where you try to recreate a SimpleObj for a key which already exists.
After digging around I came up with my own solution. There were two main problems to overcome - recursion and dealing with nodes that refer to not-yet-present parents. Here is my solution. It tries to assign objects to their parents recursively and if it fails, it creates a list of orphans. Than, it iterates over orphaned nodes list until all of them are in place. I tested this on multiple configs and it looks like it always works (provided that the input is correct meaning no repetitions or cyclic references etc).
from __future__ import annotations
from typing import List
class SimpleObj:
def __init__(self, parent_id: int, own_id: int):
self.own_id = own_id
self.parent_id = parent_id
self.children_objects = [] # type: List[SimpleObj]
def assign_to_children(self, what_to_assign: SimpleObj):
if what_to_assign.parent_id == self.own_id:
self.children_objects.append(what_to_assign)
return True
else:
for child in self.children_objects:
if child.assign_to_children(what_to_assign=what_to_assign):
return True
def __repr__(self):
return f"ID: {self.own_id}, PARENT: {self.parent_id}"
test_objects_list = [SimpleObj(own_id=69, parent_id=70),
SimpleObj(own_id=59, parent_id=71),
SimpleObj(own_id=70, parent_id=71),
SimpleObj(own_id=71, parent_id=1),
SimpleObj(own_id=1, parent_id=0),
SimpleObj(own_id=2, parent_id=1),
SimpleObj(own_id=44, parent_id=1),
SimpleObj(own_id=6, parent_id=44),
SimpleObj(own_id=14, parent_id=10),
SimpleObj(own_id=10, parent_id=1)]
def create_tree_from_list_of_obj(list_in: List[SimpleObj]):
# find root
root = [obj for obj in list_in if obj.parent_id == 0][0]
list_in.remove(root)
print(root)
orphans = []
# do the actual work
for obj in list_in:
found = root.assign_to_children(obj)
print(f"Found {obj.own_id}") if found else print(f"Not found {obj.own_id}")
if not found:
orphans.append(obj)
print(f"Adding orphaned node with id {obj.own_id}")
while orphans:
print(f"\nTrying to fill in {len(orphans)} orphaned nodes...")
for orphaned_node in orphans[:]:
found = root.assign_to_children(orphaned_node)
if found:
print(f"Found {orphaned_node.own_id}")
orphans.remove(orphaned_node)
else:
print(f"Not found {orphaned_node.own_id}")
return root
tree = create_tree_from_list_of_obj(test_objects_list)
Got a schoolwork to do showroom with 2 classes: Car & Node, while Node data contain Car class with its data. Then I have to make a Linked list, should be doubly, but I think a simple should work as well, with Nodes containing Cars. The only function in Linked list is inserting a new Node with new Car. It should be sorted by price of cars upwardly.
Tried this, but it keeps telling me
TypeError: '<' not supported between instances of 'NoneType' and 'NoneType'
class Car:
def __init__(self, id = None, name = None, brand = None, price = None, active = None):
self.id = id
self.name = name
self.brand = brand
self.price = price
self.active = active
class Node:
def __init__(self, data):
self.next = None
self.data = Car()
class LinkedList:
def __init__(self):
self.head = Node(None)
def insertNode(self, car):
newNode = Node(car)
curNode = self.head
if self.head.data is None:
self.head = newNode
if newNode.data.price < curNode.data.price:
newNode.next = curNode
self.head = newNode
else:
while curNode.next is not None and curNode.next.data.price <= newNode.data.price:
curNode = curNode.next
newNode.next = curNode.next
curNode.next = newNode
db = LinkedList()
def init(cars):
for car in cars:
db.insertNode(car)
def add(car):
db.insertNode(car)
Did I miss something, 'cause I think it should be working.
In Node.__init__ you have the line self.data = Car() which creates a Car instance using the default values (which are all None). That means that the price of every Car in the list is None. Later, you are getting an exception when you try comparing prices with newNode.data.price < curNode.data.price because you can't compare None values.
You probably need to replace self.data = Car() with something else. It's not obvious to me from your current code where the car data is supposed to come from or what format it is in. If the cars sequence you're iterating over in the top level init function is a list of Car instances already, then you should probably just do self.data = data in Node.__init__. Otherwise you'll need to do something else to extract the car data and pass it to the Car constructor. You may also want to consider getting rid of the default arguments to Car.__init__, since it doesn't seem to make much sense to create a car without them.
I see several problems, mainly regarding type consistency, in your code. You should maybe rethink what exactly the class structure here is supposed to do, how to set the default values etc. Also: Do you want to have the nodes next variable to be another node?
Assuming the following: We have Cars. Each Car has a Name, Brand and pricetag. We want two cars to be connected by a Node. And we want lists that can hold nodes and allow us to insert a new Node. Insertion should happen such that the node hierarchy connects cars in ascending price value. Two neighboring nodes share one car. You could write this as something like:
class Car:
def __init__(self, name = " ", brand = " ", price = 0):
self.name = name
self.brand = brand
self.price = price
class Node:
def __init__(self,car1,car2):
assert type(car1) == type(car2) == Car
if car1.price > car2.price:
self.next = car1
self.current = car2
else:
self.next = car2
self.current = car1
class LinkedList:
def __init__(self,firstnode):
self.ListOfNodes = [firstnode]
def insertNode(self, car):
for i in range(0,len(self.ListOfNodes)):
curnod = self.ListOfNodes[i]
newnod = Node(car,car)
if car.price < curnod.current.price:
if i<len(self.ListOfNodes): #If its not the last node
newnod.next = curnod.current
if i>0: #If its not the first node, i.e. it has a predecessor
ListOfNodes[i-1].next = newnod.current
self.ListOfNodes.insert(i,newnod)
return
elif car.price < curnod.next.price:
newnod.current = curnod.current
curnod.current = car
self.ListOfNodes.insert(i,newnod)
return
newnod.current = self.ListOfNodes[-1].next #this is only reached if the price is higher than all before
self.ListOfNodes.append(newnod)
car1 = Car(name = "baby",brand= "honda", price = 1000)
car2 = Car(name = "yomomma",brand= "Benz", price = 10)
car3 = Car(name = "PussyWagon",brand= "Dodge", price = 100)
car4 = Car(name = "FakeTaxi",brand= "HellNah", price = 10000000)
car5 = Car(name = "LondonTaxi",brand= "ChumBucket", price = 1)
p = Node(car2,car1)
lst = LinkedList(p)
lst.insertNode(car3)
lst.insertNode(car4)
lst.insertNode(car5)
It's very generic but it should work.
need a help with Dijkstra. I found a lot of codes on the internet, but I can't use any of them, because I'm not given a graph, but just lists of Vertexes & Edges into createGraph function. It's a homework and I gotta have some attributes in classes.
This is what I have:
class Vertex:
def __init__(self, id, name):
self.id = id
self.name = name
self.minDistance = float('inf')
self.previousVertex = None
self.edges = []
self.visited = False
class Edge:
def __init__(self, source, target, weight):
self.source = source
self.target = target
self.weight = weight
class Dijkstra:
def __init__(self):
self.vertexes = []
self.result = 0
def createGraph(self, vertexes, edgesToVertexes):
for i in range(len(vertexes)):
self.vertexes.append(vertexes[i])
for j in range(len(edgesToVertexes)):
if edgesToVertexes[j].source == vertexes[i].id:
vertexes[i].edges.append(edgesToVertexes[j])
def getVertexes(self):
return self.vertexes
def findMinID(self):
maxDistance = 1000000
curVertex = None
result = None
for i in range(len(self.vertexes)):
self.vertexes[i] = curVertex
if curVertex.visited is False and curVertex.minDistance < maxDistance:
curVertex = result
curVertex.minDistance = maxDistance
else:
pass
self.result = result
return
def computePath(self, sourceId):
start = None
end = None
road = None
while start is None:
if Vertex.id == sourceId:
start = Vertex
start.minDistance = 0
start.visited = True
for i in range(len(start.edges)):
start.edges[i].target = end
start.edges[i].weight = road
if road < end.minDistance:
end.minDistance = start.minDistance + road
end.previousVertex = start.id
else:
pass
self.findMinID()
self.computePath(self.result.id)
I'm still beginner so I tried to keep it simple, but it's not working as it raises error:
'type' object is not subscriptable
or:
AttributeError: type object 'Vertex' has no attribute 'id'
which makes absolutely no sense to me why.
I can use any help, thanks in advance!
When you put the line:
self.vertexes = Vertex
you are assigning the variable to the actual class. Probably what you wanted to do was make an empty list, as you append to it later:
self.vertexes = []
I would assume this is where the error comes from, as if you ever try to iterate over self.vertexes, you are iterating over the Vertex class, which is impossible and throws that error.
You also have later:
start = Vertex
Try initializing the start, like:
start = Vertex(sourceId, "vertex")
Also, the line before that you have
if Vertex.id == sourceId:
meaning that you might want to make the id variable in Vertex static:
class Vertex:
id = 0
def __init__(self, id, name):
self.id = id
id += 1
Some suggestions: class tutorial in python
Edit:
To find the vertex that has the id you want, use a filter:
start = None
for v in self.vertexes:
if v.id == sourceId:
start = Vertex(sourceId, v.name)
start.minDistance = 0
break