When I insert a new node I get AttributeError: 'Node' object has no attribute 'set_next'. I can't really understand why, because in my Node class I have a method set_next. And isn't that the one I'm calling?
class Node(object):
def __init__(self, val):
self.val = val
self.next = None
def get_data(self):
return self.val
def set_data(self, val):
self.val = val
def get_next(self):
return self.next
def set_next(self, next):
self.next = next
class LinkedList(object):
def __init__(self, head=None):
self.head = head
self.count = 0
def get_count(self):
return self.count
def insert(self, data):
new_node = Node(data)
new_node.set_next()
self.head = new_node
self.count += 1
The expected output is that the new node should be the new head node.
This will fix the AttributeError and the subsequent TypeError.
class Node(object):
def __init__(self, val):
self.val = val
self.next = None
# fixed indentation here
def get_data(self):
return self.val
def set_data(self, val):
self.val = val
def get_next(self):
return self.next
def set_next(self, next):
self.next = next
class LinkedList(object):
def __init__(self, head=None):
self.head = head
self.count = 0
def get_count(self):
return self.count
def insert(self, data):
new_node = Node(data)
# fix logic here
new_node.set_next(self.head)
self.head = new_node
self.count += 1
Testing
linked_list = LinkedList()
linked_list.insert('hello')
linked_list.insert('world')
print(linked_list.count)
print(linked_list.head.val)
print(linked_list.head.next.val)
outputs
2
world
hello
Note that, as you can see, this LinkedList inserts only at the front of the list, not the end.
Bonus
If you want to iterate over the list, use this method
def __iter__(self):
node = self.head
while node is not None:
yield node.val
node = node.next
With your indentation as it stands,
class Node(object):
def __init__(self, val):
self.val = val
self.next = None
def get_data(self):
return self.val
get_data and the following functions, including set_next are local to the __init__ method.
So, as the error says, the "Nodeclass does not have aset_next` method.
You need to pull them back:
class Node(object):
def __init__(self, val):
self.val = val
self.next = None
def get_data(self):
return self.val
#... and the rest
This will give your further problems, but fix your initial problem.
Next, you will see
File "linked.py", line 28, in insert
new_node.set_next()
TypeError: set_next() missing 1 required positional argument: 'next'
As was said in the comments, you need to pass this a value.
I suspect you are trying to set next on the head or final node to this new_node.
I tried this and hope this helps you:
class Node(object):
def __init__(self, val):
self.val = val
self.next = None
def get_data(self):
return self.val
def set_data(self, val):
self.val = val
def get_next(self):
return self.next
def set_next(self, next):
self.next = next
class LinkedList(object):
def __init__(self, head=None):
self.head = head
self.count = 0
def get_count(self):
return self.count
def insert(self, data):
new_node = Node(data)
new_node.set_next(self.head)
self.head = new_node
self.count += 1
>>> itemList = LinkedList()
>>> itemList.insert(38)
>>> itemList.insert(40)
>>> itemList.get_count()
2
Related
Can someone explain how are we able to access value in class DoublyLinkedList even when it is an attribute of class Node.
class Node:
def __init__(self, value):
self.value = value
self.next = None
self.prev = None
class DoublyLinkedList:
def __init__(self, value):
new_node = Node(value)
self.head = new_node
self.tail = new_node
self.length = 1
def print_list(self):
temp = self.head
while temp is not None:
print(temp.value)
temp = temp.next
Pls look temp.value of print_list function
I have a LinkedList class that has close to 200 lines of code. I would like to make a new class LLCircular(LinkedList) by always making sure that any myLL.tail.next is myLL.head. I believe I would need to update append(), push(), remove(), etc. accordingly. Is there a way I can do this to keep the original LinkedList class intact? Maybe a decorator or some dunder method?
For brevity's sake, if reading the code, my push() method is just the inverse of append(). I also have a pop() and remove() method, which would need to be updated, if I just rewrite those methods. As I am trying to avoid that approach, I am not posting that part of the code.
class LinkedListNode:
def __init__(self, value, nextNode=None, prevNode=None):
self.value = value
self.next = nextNode
self.prev = prevNode
def __str__(self):
return str(self.value)
class LinkedList:
def __init__(self, values=None):
self.head = None
self.tail = None
if values is not None:
self.append(values)
def __str__(self):
values = [str(x) for x in self]
return ' -> '.join(values)
def append(self, value=None):
if value is None:
raise ValueError('ERROR: LinkedList.py: append() `value` PARAMETER MISSING')
if isinstance(value, list):
for v in value:
self.append(v)
return
elif self.head is None:
self.head = LinkedListNode(value)
self.tail = self.head
else:
''' We have existing nodes '''
''' Head.next is same '''
''' Tail is new node '''
self.tail.next = LinkedListNode(value, None, self.tail)
self.tail = self.tail.next
if self.head.next is None:
self.head.next = self.tail.prev
return self.tail
'''class LLCircular(LinkedList):'''
''' ??? '''
Test Code:
foo = LinkedList([1,2,3])
foo.tail.next = foo.head #My LL is now circular
cur = foo.head
i = 0
while cur:
print(cur)
cur = cur.next
i +=1
if i>9:
break
What you want is to call your LinkedList base class functions using the super keyword, and then add the slight modifications to the LLCircular class function, i.e:
class LLCircular(LinkedList):
def append(self, value=None):
super(LLCircular, self).append(value)
# In addition to having called the LinkedList append, now you want
# to make sure the tail is pointing at the head
self.tail.next = self.head
self.head.prev = self.tail
If it is "circular" it won't need a tail or head, would it?
Nor "append" makes sense - insert_after and insert_before methods should be enough - also, any node is a reference to the complete circular list, no need for different objects:
class Circular:
def __init__(self, value=None):
self.value = value
self.next = self
self.previous = self
def insert_after(self, value):
node = Circular(value)
node.next = self.next
node.previous = self
self.next.previous = node
self.next = node
def insert_before(self, value):
node = Circular(value)
node.next = self
node.previous = self.previous
self.previous.next = node
self.previous = node
def del_next(self):
self.next = self.next.next
self.next.previous = self
def __iter__(self):
cursor = self.next
yield self
while cursor != self:
yield cursor
cursor = cursor.next
def __len__(self):
return sum(1 for _ in self)
This is how I am defining my linkedList
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
I am trying to convert a string to a linkedList
stringTotal = "abc"
head = stringToListNode(stringTotal)
#this method should return a -> b -> c
def stringToListNode(stringTotal):
for i in stringTotal:
currentNode = ListNode(i)
How can I get the next letter of the string and make it the next node?
Try this:
def stringToListNode(stringTotal):
previousNode = None
first = None
for i in stringTotal:
currentNode = ListNode(i)
if first is None:
first = currentNode
if previousNode is not None:
previousNode.next = currentNode
previousNode = currentNode
return first
One nice way to do this might be to define a from_string classmethod on your ListNode class that will recursively build a linked list for you and return the head:
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
#classmethod
def from_string(cls, s):
if s:
n = cls(s[0])
n.next = ListNode.from_string(s[1:])
return n
n = ListNode.from_string('hello')
print(n.next.next.next.next.val)
>>> 'o'
You can create an insert method as an attribute of ListNode, that can be called on the next attribute should that latter already store a node of ListNode:
class ListNode(object):
def __init__(self, x=None):
self.val = x
self.next = None
def insert(self, val):
if self.val is None:
self.val = val
else:
getattr(self.next, 'insert', lambda x:setattr(self, 'next', ListNode(x)))(val)
def __str__(self):
return '{}, {}'.format(self.val, str(self.next) if self.next else '')
def __repr__(self):
return 'List(<{}>)'.format(str(self))
#classmethod
def insert_vals(cls, s):
l = cls()
for i in s:
l.insert(i)
return l
_list = ListNode.insert_vals('abc')
print(_list)
Output:
List(<a, b, c, >)
Note, however, that the operation accomplished in method insert can also be performed as a simple function, however, it is not as clean as an instance attribute:
class ListNode(object):
def __init__(self, x=None):
self.val = x
self.next = None
def __str__(self):
return '{}, {}'.format(self.val, str(self.next) if self.next else '')
def __repr__(self):
return 'List(<{}>)'.format(str(self))
def insert_val(_l:ListNode, value:str) -> None:
if _l.val is None:
_l.val = value
else:
if isinstance(_l.next, ListNode):
insert_val(_l.next, value)
else:
_l.next = ListNode(value)
_l = ListNode()
for i in 'abc':
insert_val(_l, i)
>>>_l
Output:
List(<a, b, c, >)
class Node(object):
def __init__(self, data = None, next = None):
self.data = data
self.next_node = next
def get_data(self):
return self.data
def get_next(self):
return self.next_node
def set_next(self, new_next):
self.next_node = new_next
class LinkedList(object):
def __init__(self, head = None):
self.head = head
def insert(self, data):
new_node = Node(data, None)
if self.head is None:
self.head = new_node
else:
new_node.next = self.head
self.head = new_node
def print_list(self):
temp = self.head
while temp!=None:
print(temp.data)
if temp.next != None:
temp = temp.next
s = LinkedList()
s.insert(3)
s.insert(4)
s.insert(5)
s.insert(6)
s.print_list()
I always get this Node object has no attribute next in the console. It prints the linkedlist but how do I get rid of that warning. What extra condition should I put?
In LinkedList, you keep accessing the node’s next node using the property name next but in the Node type, you actually defined the next pointer to be called next_node.
So either change the Node definition so the pointer is just called next, or change the usages in LinkedList to refer to node.next_node instead of just node.next
I have the following Linked List implementation. There is a problem with the printlist() function. The while loop is turning an error that there is no attribute next for self. Is there a better way to write this function? Thank you!!!
class Node:
def __init__(self, data, next=None):
self.data=data
def _insert(self, data):
self.next=Node(data)
def _find(self, data):
if self.data==data:
return self
if self.next is None:
return None
while self.next is not None:
if self.next.data==data:
return self.next
return None
def _delete(self, data):
if self.next.data == data:
temp=self.next
self.next =self.next.next
temp=None
def _printtree(self):
while self:
print self.data,
self=self.next
class LinkedList:
def __init__(self):
self.head=None
def insert(self, data):
if self.head:
self.head._insert(data)
else:
self.head=Node(data)
def find(self, data):
if self.head.data==data:
return self.head
return self.head._find(data)
def delete(self, data):
if self.head.data==data:
head=None
return
self.head._delete(data)
def printtree(self):
self.head._printtree()
add next attribute to Node's ini method
you should define printtree of LinkedList this way:
def printree(self):
current_node = self.head
print current_node.data
while current_node.next is not None:
print current_node.next.data
current_node = current_node.next
adding a repr method will make your code nicer