Wrapper Class in Python for Linked List - python-3.x

I am absolutely new to Wrapper Classes in Python. I was trying to implement it in a program of linked list where multiple linked list are in use. My code is:
def nodewrap(cls):
class Nodewrap:
def __init__(self):
self.head = None
self.tail = None
return Nodewrap
#nodewrap
class Node:
def __init__(self,data):
self.data = data
self.next = None
class Intersection:
def addnode(self,d):
newnode = Node(d)
if head == None:
head = tail = newnode
else:
tail.next = newnode
tail = newnode
obj1 = Intersection()
obj2 = Intersection()
obj3 = Intersection()
s1 = int(input("Enter size of 1st list : \n"))
for i in range(s1):
obj1.addnode(int(input("Enter the data : \n")))
s2 = int(input("Enter size of 1st list : \n"))
for i in range(s2):
obj2.addnode(int(input("Enter the data : \n")))
temp1 = obj1.head
for i in range(s1):
temp2 = obj2.head
for j in range(s2):
if temp1.data == temp2.data:
obj3.addnode(temp1.data)
break
temp2 = temp2.next
temp1 = temp1.next
print("Intersection is :")
temp = obj3.head
while temp!=None:
print(temp.data,end=" ")
temp = temp.next
I thought of using a wrapper class to wrap the class Node instead of using objects of the class Intersection only with data fields as head, tail. But it is giving me some sort of error with regards to init().
Please help.
I was trying to learn it from here:
https://www.geeksforgeeks.org/wrapper-class-in-python/

I think I understand what you want to do, but I think that you don't want to use a decorator, but you want to inherit from NodeWrap class
class Nodewrap:
head = None
tail = None
class Node(NodeWrap):
def __init__(self,data):
self.data = data
self.next = None
But I don't see any reason why to inherit this way. This should be enough, for a linked list. I have added is_first and is_last property
from __future__ import annotations
class Node:
prev_node = None
next_node = None
def __init__(self, data):
self.data = data
def add_node(self, node: Node) -> None:
if self.prev_node is not None:
raise ValueError('Previous node already defined.')
self.next_node = node
node.prev_node = self
#property
def is_first(self) -> bool:
return self.prev_node is None
#property
def is_last(self) -> bool:
return self.next_node is None
You can implement next, iter and create an Iterator class.
I don't recommend using next as the variable name.
from __future__ import annotations reference here. It's just for self reference annotation.

Related

Defining a global variable inside a class vs. defining inside a method

I am trying to find the vertical width if a binary tree as defined in this link; https://practice.geeksforgeeks.org/batch/dsa-4/track/DSASP-Tree/problem/vertical-width-of-a-binary-tree
My question is regarding defining a global variable inside a class vs defining it inside a method. Here is my code, which is working as expected in the present form;
class Node:
#global dnew
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def vertical_width(self):
#dnew = {self.data: 0}
#print(self.data, dnew)
if self is None:
return
# if we move left decrease value by 1
if self.left != None:
dnew[self.left.data] = dnew[self.data] - 1
self.left.vertical_width()
print('left', dnew)
# if we move right increase value by 1
if self.right != None:
dnew[self.right.data] = dnew[self.data] + 1
self.right.vertical_width()
print('right', dnew)
return dnew
def mainfn(self):
global dnew
dnew = {self.data:0}
result = self.vertical_width()
return len(set(result.values()))
class Tree:
def __init__(self,root):
self.root = root
# define a tree as an example to test the code
node = Node(1)
node.left = Node(2)
node.left.left = Node(3)
node.left.right = Node(4)
node.right = Node(5)
#node.right.left = Node(6)
mytree = Tree(node)
res = mytree.root.mainfn()
Question is, if we just define global dnew inside the Node class rather than defining it inside the mainfn(), we get following error message;
NameError: name 'dnew' is not defined
But isn't that if we define a variable with global keyword, it shd be accessible by all methods in a class.Can I please get some help to understand this concept?

code should not return any node object(Element)

https://gist.github.com/manaidu-2002/3f7eb60b8521201eba6548ca23cec053
Code returning Node Object(Element), please check the test cases and help me with this
"""Add a couple methods to our LinkedList class,
and use that to implement a Stack.
You have 4 functions below to fill in:
insert_first, delete_first, push, and pop.
Think about this while you're implementing:
why is it easier to add an "insert_first"
function than just use "append"?"""
class Element(object):
def __init__(self, value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def append(self, new_element):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new_element
else:
self.head = new_element
def insert_first(self, new_element):
"Insert new element as the head of the LinkedList"
new_element.next = self.head
self.head = e_insert
def delete_first(self):
"Delete the first (head) element in the LinkedList as return it"
temp = self.head
if temp == None:
return None
s= temp
self.head = temp.next
return s
class Stack(object):
def __init__(self,head=None):
self.ll = LinkedList(head)
def push(self, new_element):
"Push (add) a new element onto the top of the stack"
temp = self.ll.head
while temp.next :
temp = temp.next
temp.next = new_element
def pop(self):
"Pop (remove) the first element off the top of the stack and return it"
if self.ll.head.next == None :
temp = self.ll.head
e= temp
temp = None
return e
elif self.ll.head.next:
temp = self.ll.head
while temp.next.next:
temp = temp.next
e= temp.next
temp.next = None
return e
return None
# Test cases
# Set up some Elements
e1 = Element(1)
e2 = Element(2)
e3 = Element(3)
e4 = Element(4)
# Start setting up a Stack
stack = Stack(e1)
# Test stack functionality
stack.push(e2)
stack.push(e3)
print(stack.pop().value)
print(stack.pop().value)
print(stack.pop().value)
print(stack.pop())
stack.push(e4)
print(stack.pop().value)
First of all, there is an unused name reference in your code: e_insert. This should read new_element.
The main issue is that your Stack class is not re-using the code you already have in your LinkedList class. In the new code you have written there are several mistakes in how you deal with next, but taking a step back, you are making a critical mistake in thinking that the top of the stack should be at the tail of the linked list, but that is very inefficient. The top of the stack should be at the head of the linked list. It is at that side that you can easily remove and insert elements without having to iterate the list.
So take these points into consideration:
Reuse the code you already have for LinkedList. In other words, call the methods defined on the LinkedList class.
The top of the stack is at the head of the linked list.
That means the Stack class can be as simple as this:
class Stack(LinkedList):
def __init__(self, head=None):
self.ll = LinkedList(head)
def push(self, new_element):
self.ll.insert_first(new_element)
def pop(self):
return self.ll.delete_first()

How to define and use a funciton outside a class?

In the following code for linked list implementation in Python3. How do I define and call the functions such as reverse() and display() outside of the class. Like, how should create a function that performs operations like display() and recerse(). How should I pass a LinkedList object and how to access its members, so that I am able to do desired operations?
PS : I removed other functions because I was not able to post this question.
I am not asking about importing the class file to use in other .py files.
class Node:
def __init__(self,data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def display(self):
curr = self.head
while curr != None:
print(curr.data + '->', end = ' ')
curr = curr.next
print('NULL')
def append(self, data):
'''
statements....
'''
def length(self):
ptr = self.head
count = 0
while ptr.next != None:
count += 1
ptr = ptr.next
print(count+1)
def reverse(self):
pre = None
cur = self.head
while cur != None:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
self.head = pre
self.display()
l = LinkedList()
l.append('A')
l.append('B')
l.append('C')
l.append('D')
l.prepend('E')
l.display()
not sure I'm understanding your question correctly, but if I am it seems that you just want to take all of the code, minus the program code (from "l=LinkedList()" down in your example), and save it to a python file, then at the top of any python code you need to use your class in, import your file.
If your class file is not in the same directory as the code from which you wish to use the class, you'll need to keep the class file in a directory in your path:
import sys
print(sys.path)
and if you wish to add a directory to your path, you can:
sys.path.append('<directory')
At that point, once you
import LinkedList
(assuming your class file is called LinkedList.py) you'll be able to define variables using your class and use it the same as you would in your example, so your code file would look something like:
import LinkedList
l = LinkedList()
l.append('A')
l.append('B')
l.append('C')
l.append('D')
l.prepend('E')
l.display()
Or am I just not reading your question correctly?
I added the prepend and append method for you, I'm not sure if this is what you were referring to. Also, if you're looking for static vs class methods, you can check those out here: Class method vs static method in Python
With static methods you can return instances of a specified class by using arguments to the static method. Check out the link above to use class functions outside of their instances.
Here is the Python code:
class Node:
def __init__(self,data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def display(self):
curr = self.head
while curr != None:
print(curr.data + '->', end = ' ')
curr = curr.next
print('NULL')
def append(self, data):
data_node = Node(data)
data_node.next = self.head
self.head = data_node
def prepend(self, data):
ptr = self.head
while ptr.next != None:
ptr = ptr.next
ptr.next = Node(data)
def length(self):
ptr = self.head
count = 0
while ptr.next != None:
count += 1
ptr = ptr.next
print(count+1)
def reverse(self):
pre = None
cur = self.head
while cur != None:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
self.head = pre
self.display()
l = LinkedList()
l.append('A')
l.append('B')
l.append('C')
l.append('D')
l.prepend('E')
l.display()

Understanding the "self" in classes for Python

I'm trying to understand the solution provided for reversing a linked list. In particular, I don't get why for the very last line we write:
self.head=prev
and not
current=prev
since
current=self.head
I know my reasoning is flawed, that's why I came here for help. Thank you in advance.
class Node:
# Constructor to initialize the node object
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
# Function to initialize head
def __init__(self):
self.head = None
def reverse(self):
prev = None
current = self.head
while(current is not None):
next = current.next
current.next = prev
prev = current
current = next
self.head = prev
= is not equality like in math, it is the assignment/binding operator.
Therefore, after:
current=self.head
current=prev
current will have the value of prev and self.head will have nothing to do with current nor will be modified.

reverse chain of nodes python

Need some help with something I'm working on regarding making a chain of nodes. I need to move the last index to the second index using a the Node class which I have imported.
from Node import Node:
def reverse_chain(list):
if list is None: return
head = list
tail = list.next
reverse_chain(tail)
print(head,end = " ")
This is the code I wrote but at the moment it doesn't make sense so I'm still working on it
my node.py file has this code in it:
class Node:
def __init__(self, init_data):
self.data = init_data
self.next = None
def get_data(self):
return self.data
def get_next(self):
return self.next
def set_data(self, new_data):
self.data = new_data
def set_next(self, new_next):
self.next = new_next
def __str__(self):
return str(self.data)
I am trying to produce this output:
node_1 = Node('John')
node_2 = Node('Bill')
node_3 = Node('monkey')
node1.set_next(node2)
node2.set_next(node3)
reverse_chain(node1)
print(node1.get_data(), end = ' ')
print(node1.get_next().get_data(), end = ' ')
print(node1.get_next().get_next().get_data(), end = ' ')
should produce John monkey Bill

Resources