Learn practical skills, build real-world projects, and advance your career
class Node:
    def __init__(self,val=None):
        self.val=val;
        self.next=None

class LinkedList:
    def __init__(self):
        self.head=None

def push(self,val):
    new_node=Node(val)
    
    if self.head is None:
        self.head=new_node
        return
    
    temp=self.head
    
    while temp.next is not None:
        temp=temp.next
        
    temp.next=new_node
    
LinkedList.push=push

def pop(self):
    if self.head is None:
        raise Exception("List is Empty cannot pop")
        
    if self.head.next is None:
        val=self.head.val
        self.head=None
        return val
    
    temp=self.head
    while temp.next is not None:
        prev=temp
        temp=temp.next
        
    val=temp.val
    prev.next=None
    return val
LinkedList.pop=pop

def insert(self,index,val):
    new_node=Node(val)
    if index==0:
        new_node.next=self.head
        self.head=new_node
        return
    
    temp=self.head
    counter=0
    while temp is not None and counter<index:
        prev =temp
        temp=temp.next
        counter+=1
    prev.next=new_node
    new_node.next=temp
    
LinkedList.insert=insert

def remove(self ,val):
    
    temp=self.head
    
    if temp is not None:
        if temp.val==val:
            self.head=temp.next
            temp=None
            return
    while temp is not None:
        if temp.val==val:
            break
        prev=temp
        temp=temp.next
    
    if temp is None:
        return
    
    prev.next=temp.next
    
LinkedList.remove=remove


def get(self,index):

    counter=0
    temp=self.head
    
    while temp is not None:
        if counter==index:
            val=temp.val
            return val
        temp=temp.next
        counter+=1
        
    if temp is None or counter<index:
        raise IndexError("list index out of range")
        
LinkedList.get=get

def len(self):
    temp=self.head
    counter=0
    while temp is not None:
        temp=temp.next
        counter+=1
        
    return counter
    
LinkedList.len=len


def __str__(self):
    r="["
    temp =self.head
    while temp is not None:
        r+=str(temp.val)+", "
        temp=temp.next
    r=r.rstrip(", ")
    r+="]"
    return r
LinkedList.__str__=__str__
def remove_at(self,index):
    counter=0
    temp=self.head
    
    if self.head is None:
        return
        
    while temp is not None:
        if index==counter:
            val=temp.val
            self.head=temp.next
            return val
        prev=temp
        temp=temp.next
        counter+=1
        if(counter==index):
            val=temp.val
            prev.next=temp.next
    if counter<index:
        raise IndexError("list index out of range")
    
    return val
LinkedList.remove_at=remove_at
def reverse(self):
    prev=None
    current =self.head
    if current ==None or current.next==None:
        return None
    while current!=None:
        temp=current.next
        current.next=prev
        prev=current
        current=temp
    self.head=prev
LinkedList.reverse=reverse
l=LinkedList()
l.push(1)
l.push(2)
l.push(3)
l.push(4)
l.push(5)

print(l)
[1, 2, 3, 4, 5]
l.reverse()