create Linkedlist from list
Question:
Can anyone help me understand why I get this error ?
I design a Linkedlist Class like this where I want to create a linkedlist from an array:
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self, head=None):
self.head = head
def arrayToLL(X):
'''Create LL from a list'''
if not X:
return LinkedList()
ll = LinkedList(Node(X[0]))
last = ll.head
for i in range(1, len(X)):
last.next = Node(X[i])
last = last.next
return ll
def __str__(self) -> str:
linked_list = ''
node = self.head
while node is not None:
linked_list += str(node.val)
node = node.next
if node:
linked_list += ' -> '
return linked_list
When I do the implementation as I learnt for classes.
I instantiate the class first, then apply its methods
ll = LinkedList()
ll.arrayToLL([1, 2 , 3])
print(ll)
I got this Error: arrayToLL() takes 1 positional argument but 2 were given
** But when I add the ‘self’ argument to the arrayToLL(self, X) method:
and do the previous implementation I got a blank line.
Can anyone tell me why the LL wasn’t printed?? ‘1 -> 2 -> 3’
ll = LinkedList()
ll.arrayToLL([1, 2 , 3])
print(ll)
#Blank line as result
** Another thing that confuses me is that: when I call the function arrayToLL(X) directly without instantiating the linkedlist and without using self on it the LL was printed: without error. Why this happen? what I can’t use ll = LinkedList() then apply ll.methods
ll = LinkedList.arrayToLL([1, 2 , 3])
print(ll)
‘1 -> 2 -> 3’
What I did: I tried to add and/or remove ‘self’ argument in arrayToLL method an see the results.
WhatI am expecting: is to understand why in 3 cases the result change!!!
For the first case without self in arrayToLL method => I got error of missing argument
In the second case where I add the ‘self’ argument I got a blank result
In the third case where I remove ‘self’ from argument and print the method directly (LinkedList.arrayToLL([1, 2 , 3])) without instantiating the ll = LinkedList() I got the result! why this happens? Thanks
Answers:
There’s a good article about linked lists
https://realpython.com/linked-lists-python/
That should help you gain some understanding
This code does the trick:
class Node:
def __init__(self, val, next_node=None):
self.val = val
self.next = next_node
class LinkedList:
def __init__(self, head=None):
self.head = head
def array_to_ll(self, X):
if not X:
return self
self.head = Node(X[0])
curr_last = self.head
for elt in X:
curr_last.next = Node(elt)
curr_last = curr_last.next
return self
def __str__(self):
ll = ""
node = self.head
while node is not None:
ll += str(node.val)
node = node.next
if node:
ll += ' -> '
return ll
if __name__ == "__main__":
ll = LinkedList()
ll.array_to_ll([1, 2, 3])
print(ll)
Here, you missed the self
parameter of the array_to_ll
method. This parameter is filled by the object you called the method with, i.e. in ll.array_to_ll([1, 2, 3])
, the self
parameter is filled with ll
, and the X
parameter is filled by [1, 2, 3]
. (In fact it is the first parameter that is filled with the object, whatever its name, though it is a strong convention that this first parameter referring to the object the method is called upon should be named self
in Python). This also explains the error takes 1 positional argument, but 2 were given
as you gave ll
and [1, 2, 3]
, but the method only expected X
.
As a side-note, you don’t have to return anything with array_to_ll
if there is no other uses for this method than to "load" your linked list. (In fact, the returned object in your code and mine is not stored in a variable, so it is lost. This does not matter as we already have a variable which stores it: ll
). We could then rewrite it:
def array_to_ll(self, X):
if not X:
return # This is only here to exit the function in case X is None
self.head = Node(X[0])
curr_last = self.head
for elt in X:
curr_last.next = Node(elt)
curr_last = curr_last.next
EDIT: @trincot’s answer followed the other path and is also interesting to look into. While I have made this method depend on self
(i.e. the instance) (which may or may not be pertinent), he made it static (i.e. depend on the class).
I got this Error: arrayToLL()
takes 1 positional argument but 2 were given
This is expected, because ll
is passed as first argument, and your method did not define a parameter for it (usually called self
)
But when I add the self
argument to the arrayToLL(self, X) method: and do the previous implementation I got a blank line.
That happens because self
is not used by that method, so ll
is still empty after the call. Instead the method returns the built linked list, but then your main code is not doing anything with the returned object.
when I call the function arrayToLL(X)
directly without instantiating the linkedlist and without using self
on it the LL was printed: without error.
This is how it should be done, because your method is not really doing anything that relates to a self
. It should be called as a static method, and it would make sense to declare it that way:
@staticmethod
def arrayToLL(X):
'''Create LL from a list'''
if not X:
return LinkedList()
ll = LinkedList(Node(X[0]))
last = ll.head
for i in range(1, len(X)):
last.next = Node(X[i])
last = last.next
return ll
I see that you have made a constructor that can accept a head
node as argument. I would not do that. Instead you could use the argument list to pass values for the linked list, and this would make the arrayToLL
method obsolete. Furthermore, it is beneficial to add an __iter__
method to your class, which the __str__
method can use to do its job, but which can also serve in other scenarios.
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self, *values):
self.head = None
for value in reversed(values):
self.head = Node(value, self.head)
def __iter__(self):
node = self.head
while node:
yield node.val
node = node.next
def __str__(self) -> str:
return " -> ".join(map(str, self))
ll = LinkedList(1, 2, 3)
print(ll)
Can anyone help me understand why I get this error ?
I design a Linkedlist Class like this where I want to create a linkedlist from an array:
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self, head=None):
self.head = head
def arrayToLL(X):
'''Create LL from a list'''
if not X:
return LinkedList()
ll = LinkedList(Node(X[0]))
last = ll.head
for i in range(1, len(X)):
last.next = Node(X[i])
last = last.next
return ll
def __str__(self) -> str:
linked_list = ''
node = self.head
while node is not None:
linked_list += str(node.val)
node = node.next
if node:
linked_list += ' -> '
return linked_list
When I do the implementation as I learnt for classes.
I instantiate the class first, then apply its methods
ll = LinkedList()
ll.arrayToLL([1, 2 , 3])
print(ll)
I got this Error: arrayToLL() takes 1 positional argument but 2 were given
** But when I add the ‘self’ argument to the arrayToLL(self, X) method:
and do the previous implementation I got a blank line.
Can anyone tell me why the LL wasn’t printed?? ‘1 -> 2 -> 3’
ll = LinkedList()
ll.arrayToLL([1, 2 , 3])
print(ll)
#Blank line as result
** Another thing that confuses me is that: when I call the function arrayToLL(X) directly without instantiating the linkedlist and without using self on it the LL was printed: without error. Why this happen? what I can’t use ll = LinkedList() then apply ll.methods
ll = LinkedList.arrayToLL([1, 2 , 3])
print(ll)
‘1 -> 2 -> 3’
What I did: I tried to add and/or remove ‘self’ argument in arrayToLL method an see the results.
WhatI am expecting: is to understand why in 3 cases the result change!!!
For the first case without self in arrayToLL method => I got error of missing argument
In the second case where I add the ‘self’ argument I got a blank result
In the third case where I remove ‘self’ from argument and print the method directly (LinkedList.arrayToLL([1, 2 , 3])) without instantiating the ll = LinkedList() I got the result! why this happens? Thanks
There’s a good article about linked lists
https://realpython.com/linked-lists-python/
That should help you gain some understanding
This code does the trick:
class Node:
def __init__(self, val, next_node=None):
self.val = val
self.next = next_node
class LinkedList:
def __init__(self, head=None):
self.head = head
def array_to_ll(self, X):
if not X:
return self
self.head = Node(X[0])
curr_last = self.head
for elt in X:
curr_last.next = Node(elt)
curr_last = curr_last.next
return self
def __str__(self):
ll = ""
node = self.head
while node is not None:
ll += str(node.val)
node = node.next
if node:
ll += ' -> '
return ll
if __name__ == "__main__":
ll = LinkedList()
ll.array_to_ll([1, 2, 3])
print(ll)
Here, you missed the self
parameter of the array_to_ll
method. This parameter is filled by the object you called the method with, i.e. in ll.array_to_ll([1, 2, 3])
, the self
parameter is filled with ll
, and the X
parameter is filled by [1, 2, 3]
. (In fact it is the first parameter that is filled with the object, whatever its name, though it is a strong convention that this first parameter referring to the object the method is called upon should be named self
in Python). This also explains the error takes 1 positional argument, but 2 were given
as you gave ll
and [1, 2, 3]
, but the method only expected X
.
As a side-note, you don’t have to return anything with array_to_ll
if there is no other uses for this method than to "load" your linked list. (In fact, the returned object in your code and mine is not stored in a variable, so it is lost. This does not matter as we already have a variable which stores it: ll
). We could then rewrite it:
def array_to_ll(self, X):
if not X:
return # This is only here to exit the function in case X is None
self.head = Node(X[0])
curr_last = self.head
for elt in X:
curr_last.next = Node(elt)
curr_last = curr_last.next
EDIT: @trincot’s answer followed the other path and is also interesting to look into. While I have made this method depend on self
(i.e. the instance) (which may or may not be pertinent), he made it static (i.e. depend on the class).
I got this Error:
arrayToLL()
takes 1 positional argument but 2 were given
This is expected, because ll
is passed as first argument, and your method did not define a parameter for it (usually called self
)
But when I add the
self
argument to the arrayToLL(self, X) method: and do the previous implementation I got a blank line.
That happens because self
is not used by that method, so ll
is still empty after the call. Instead the method returns the built linked list, but then your main code is not doing anything with the returned object.
when I call the function
arrayToLL(X)
directly without instantiating the linkedlist and without usingself
on it the LL was printed: without error.
This is how it should be done, because your method is not really doing anything that relates to a self
. It should be called as a static method, and it would make sense to declare it that way:
@staticmethod
def arrayToLL(X):
'''Create LL from a list'''
if not X:
return LinkedList()
ll = LinkedList(Node(X[0]))
last = ll.head
for i in range(1, len(X)):
last.next = Node(X[i])
last = last.next
return ll
I see that you have made a constructor that can accept a head
node as argument. I would not do that. Instead you could use the argument list to pass values for the linked list, and this would make the arrayToLL
method obsolete. Furthermore, it is beneficial to add an __iter__
method to your class, which the __str__
method can use to do its job, but which can also serve in other scenarios.
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self, *values):
self.head = None
for value in reversed(values):
self.head = Node(value, self.head)
def __iter__(self):
node = self.head
while node:
yield node.val
node = node.next
def __str__(self) -> str:
return " -> ".join(map(str, self))
ll = LinkedList(1, 2, 3)
print(ll)