feat(curriculum): add linked list workshop (#61424)

Co-authored-by: Ilenia M <nethleen@gmail.com>
This commit is contained in:
Ihechikara Abba
2025-09-30 10:22:01 +01:00
committed by GitHub
parent b60dc22ea2
commit 086454dc7b
28 changed files with 1613 additions and 2 deletions
+4 -2
View File
@@ -4616,8 +4616,10 @@
]
},
"workshop-linked-list-class": {
"title": "Build a Linked List Class",
"intro": [""]
"title": "Build a Linked List",
"intro": [
"In this workshop, you'll practice working with data structures by building a linked list."
]
},
"lab-hash-table": {
"title": "Build a Hash Table",
@@ -0,0 +1,9 @@
---
title: Introduction to the Build a Linked List
block: workshop-linked-list-class
superBlock: full-stack-developer
---
## Introduction to the Build a Linked List
In this workshop, you'll practice working with data structures by building a linked list.
@@ -0,0 +1,32 @@
---
id: 687d7deea6a2a22fa8816a73
title: Step 1
challengeType: 20
dashedName: step-1
---
# --description--
In previous lessons, you learned about some common data structures. In this workshop, you'll implement a linked list.
First, create a class named `LinkedList` to represent the structure that will hold your list nodes. Add the `pass` keyword inside the class so that the test can pass.
# --hints--
You should create a class named `LinkedList`. Remember to add the `pass` keyword.
```js
({
test: () => runPython(`assert _Node(_code).has_class("LinkedList")`)
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,31 @@
---
id: 687d8c6f066877768f7ee441
title: Step 2
challengeType: 20
dashedName: step-2
---
# --description--
Inside your `LinkedList` class, replace the `pass` keyword with an inner class called `Node`. This will represent individual nodes that store data in the list.
# --hints--
You should create a `Node` class within the `LinkedList` class. Remember to add the `pass` keyword inside the `Node` class.
```js
({
test: () => runPython(`assert _Node(_code).find_class("LinkedList").has_class("Node")`)
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
class LinkedList:
pass
--fcc-editable-region--
```
@@ -0,0 +1,53 @@
---
id: 687d8e05a529a4838f1c961c
title: Step 3
challengeType: 20
dashedName: step-3
---
# --description--
Next, remove the `pass` keyword inside the `Node` class, then give the `Node` class an `__init__` method with two parameters, `self` and `element`.
Inside the method, assign `element` to `self.element`. This stores the value passed when creating a node.
# --hints--
You should define an `__init__` method inside your `Node` class.
```js
({
test: () => runPython(`assert _Node(_code).find_class("LinkedList").find_class("Node").has_function("__init__")`)
})
```
Your `__init__` method should have two parameters, `self` and `element`.
```js
({
test: () => runPython(`assert _Node(_code).find_class("LinkedList").find_class("Node").find_function("__init__").has_args("self, element")`)
})
```
You should assign `element` to `self.element` inside the `__init__` method.
```js
({
test: () => runPython(`
n = LinkedList.Node("A")
assert n.element == "A"
`)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
--fcc-editable-region--
class Node:
pass
--fcc-editable-region--
```
@@ -0,0 +1,38 @@
---
id: 687e344cc1993f7316af030c
title: Step 5
challengeType: 20
dashedName: step-5
---
# --description--
Inside the `LinkedList` class, add an `__init__` method that sets `self.length` to `0`. This initializes a counter to track how many nodes (elements) are currently in the list.
# --hints--
You should set `self.length` to `0` inside the `__init__` method of the `LinkedList` class.
```js
({
test: () => runPython(`
ll = LinkedList()
assert ll.length == 0`)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,48 @@
---
id: 687e366b3004a9831e4cbd41
title: Step 7
challengeType: 20
dashedName: step-7
---
# --description--
Add a method called `is_empty` that returns `self.length == 0`.
You'll use this to keep track of how many nodes are in the list. So, with `self.length == 0`, it returns `True`, meaning that the list has no nodes.
If `self.length` is greater than `0`, it returns `False`, meaning that the list has at least one node.
# --hints--
You should create an `is_empty` method that returns `self.length == 0`.
```js
({
test: () => runPython(`
ll = LinkedList()
assert ll.is_empty() == True
ll.length = 1
assert ll.is_empty() == False`)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,38 @@
---
id: 688003f589b875af60273dd9
title: Step 4
challengeType: 20
dashedName: step-4
---
# --description--
Still inside the `__init__` method, assign `None` to `self.next`. This sets the `next` pointer to `None`, meaning that the new node does not yet point to any other node in the list.
Later, `next` can be updated to point to another node to form the chain of a linked list.
# --hints--
Inside the `__init__` method, you should initialize the `next` attribute to `None`.
```js
({
test: () => runPython(`
n = LinkedList.Node("A")
assert n.next is None
`)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
--fcc-editable-region--
def __init__(self, element):
self.element = element
--fcc-editable-region--
```
@@ -0,0 +1,40 @@
---
id: 68800a64b06e80d9a31c131b
title: Step 6
challengeType: 20
dashedName: step-6
---
# --description--
Still in the `__init__` method of the `LinkedList` class, set `self.head` to `None`. This acts as a reference to the first node in the list. The list is empty at the moment so, you have to set it to `None`.
# --hints--
You should set `self.head` to `None` inside the `__init__` method of the `LinkedList` class.
```js
({
test: () => runPython(`
ll = LinkedList()
assert ll.head is None`)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
--fcc-editable-region--
def __init__(self):
self.length = 0
--fcc-editable-region--
```
@@ -0,0 +1,74 @@
---
id: 68857e0a49baf4751f737a2a
title: Step 9
challengeType: 20
dashedName: step-9
---
# --description--
Now, after the `is_empty` method, create a method called `add` inside the `LinkedList` class. The new method should have two parameters, `self` and `element`.
Inside your new method, create a variable named `node` and assign it a new instance of `Node` by using `self.Node(element)`. This will create a new node to be added to the linked list.
# --hints--
You should create an `add` method inside the `LinkedList` class.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").has_function("add")`
)
)
})
```
Your `add` method should have two parameters, `self` and `element`.
```js
({
test: () => runPython(`assert _Node(_code).find_class("LinkedList").find_function("add").has_args("self, element")`)
})
```
You should assign `self.Node(element)` to `node` in the `add` method.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("add").find_body().is_equivalent("node = self.Node(element)")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
--fcc-editable-region--
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
```
@@ -0,0 +1,62 @@
---
id: 68858a1b4e867acd87f6f7e8
title: Step 10
challengeType: 20
dashedName: step-10
---
# --description--
If the list is empty, then the new node becomes the first element (the `head`). Inside the `add` method, create an `if` statement that checks if the list is empty using `self.is_empty()` and assign `node` to `self.head`.
# --hints--
You should check if the list is empty by using the `is_empty()` method.
```js
({
test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("add").find_ifs()[0].find_conditions()[0]
assert _cond.is_equivalent("self.is_empty()")
`)})
```
You should assign `node` to `self.head` inside the `if` statement.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("add").find_ifs()[0].find_body().is_equivalent("self.head = node")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
--fcc-editable-region--
def add(self, element):
node = self.Node(element)
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
```
@@ -0,0 +1,56 @@
---
id: 688649c8673f842f49228a5e
title: Step 11
challengeType: 20
dashedName: step-11
---
# --description--
If the list is not empty, the method should find the last node and link the new node to its `next` pointer.
To do this, create an `else` block after the `if` block. Inside the `else` block, create a `current_node` variable and assign `self.head` to it.
# --hints--
You should assign `self.head` to `current_node` inside the `else` block.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("add").find_ifs()[0].find_bodies()[1].is_equivalent("current_node = self.head")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
--fcc-editable-region--
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
```
@@ -0,0 +1,60 @@
---
id: 68867c3898b09115d8c5140f
title: Step 13
challengeType: 20
dashedName: step-13
---
# --description--
The `while` loop you've just created enables you to go through each node in the list until the last node is reached. Once that happens, you can add the node to the list.
In the `else` block, right after the `while` block, assign `node` to `current_node.next`.
# --hints--
You should assign `node` to `current_node.next` in the `else` block.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("add").find_ifs()[0].find_bodies()[1].has_stmt("current_node.next = node")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
--fcc-editable-region--
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
```
@@ -0,0 +1,59 @@
---
id: 68868f502659139bed8e5c90
title: Step 14
challengeType: 20
dashedName: step-14
---
# --description--
After adding a new node to the list, you need to update its length. At the end of the `add` method, increment `self.length` by `1`.
# --hints--
You should increment `self.length` by `1` at the end of the `add` method.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("add").has_stmt("self.length += 1")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
--fcc-editable-region--
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
current_node.next = node
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
```
@@ -0,0 +1,88 @@
---
id: 6888d05ba074461b64f8eaca
title: Step 16
challengeType: 20
dashedName: step-16
---
# --description--
Next, you're going to create another method that will be used to remove a given element from the linked list.
Create a method called `remove` with two parameters, `self` and `element`. Inside it, create a variable called `previous_node` and assign `None` to it.
# --hints--
You should create a method called `remove`.
```js
({
test: () => assert(
runPython(`
_Node(_code).find_class("LinkedList").has_function("remove")
`)
)
})
```
Your `remove` method should have two parameters, `self` and `element`.
```js
({
test: () => runPython(`assert _Node(_code).find_class("LinkedList").find_function("remove").has_args("self, element")`)
})
```
You should assign `None` to `previous_node` in the `remove` method.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("remove").find_body().is_equivalent("previous_node = None")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
--fcc-editable-region--
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,69 @@
---
id: 6888f9827637322d4f309192
title: Step 17
challengeType: 20
dashedName: step-17
---
# --description--
Inside the `remove` method, create a variable named `current_node` and assign it the value of `self.head`.
This starts the traversal of the linked list from the first node. `current_node` will be used to keep track of the node currently being examined as you look for the node containing the specified element to remove.
# --hints--
You should assign `self.head` to `current_node` inside the `remove` method.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("remove").has_stmt("current_node = self.head")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
--fcc-editable-region--
def remove(self, element):
previous_node = None
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,85 @@
---
id: 6888fe6c745b6852ed240229
title: Step 18
challengeType: 20
dashedName: step-18
---
# --description--
Next, you'll loop through the linked list to find the node that contains the specified element to remove.
Create a `while` loop that checks when `current_node` is not `None` and when `current_node.element` is not equal to `element`. Inside the `while` loop, assign `current_node` to `previous_node`.
# --hints--
You should have a `while` loop inside the `remove` method.
```js
({
test: () => runPython(`
assert _Node(_code).find_class("LinkedList").find_function("remove").find_whiles()[0]
`)})
```
Your `while` loop should check for when `current_node` is not `None` and when `current_node.element` is not equal to `element`.
```js
({
test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("remove").find_whiles()[0].find_conditions()[0]
assert _cond.is_equivalent("current_node is not None and current_node.element != element")
`)})
```
You should assign `current_node` to `previous_node` inside the `while` loop.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("remove").find_whiles()[0]
assert _cond.is_equivalent("while current_node is not None and current_node.element != element:\\n previous_node = current_node")
`) })
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
--fcc-editable-region--
def remove(self, element):
previous_node = None
current_node = self.head
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,68 @@
---
id: 688ac1de985053329b4573d3
title: Step 19
challengeType: 20
dashedName: step-19
---
# --description--
Next, assign `current_node.next` to `current_node` in the `while` loop.
This moves the `current_node` pointer to the next node in the list during each iteration of the loop, allowing you to traverse the linked list until the element is found or the end of the list is reached.
# --hints--
You should assign `current_node.next` to `current_node` inside the `while` loop.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("remove").find_whiles()[0]
assert _cond.is_equivalent("while current_node is not None and current_node.element != element:\\n previous_node = current_node\\n current_node = current_node.next")
`) })
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
def remove(self, element):
previous_node = None
current_node = self.head
--fcc-editable-region--
while current_node is not None and current_node.element != element:
previous_node = current_node
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,70 @@
---
id: 688ac806194cfc60ba1e1767
title: Step 20
challengeType: 20
dashedName: step-20
---
# --description--
After the `while` loop, create an `if` statement that checks if `current_node` is `None`.
When this happens, the linked list has been traversed without finding the element to remove and the function should stop running. Therefore, add the `return` keyword inside the `if` body.
# --hints--
You should create an `if` statement that checks if `current_node` is `None`, and add the `return` keyword inside it.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("remove").find_ifs()[0]
assert _cond.is_equivalent("if current_node is None:\\n return")
`) })
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
def remove(self, element):
previous_node = None
current_node = self.head
while current_node is not None and current_node.element != element:
previous_node = current_node
current_node = current_node.next
--fcc-editable-region--
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,80 @@
---
id: 688acb2053ac7978a06345f1
title: Step 21
challengeType: 20
dashedName: step-21
---
# --description--
Next, create an `elif` statement that checks that `previous_node` is not `None`. Assign `current_node.next` to `previous_node.next` inside it.
With that, if the element to be removed is found and it's not in the head node, the `next` pointer of the previous node will be updated to skip over the current node (the element to be removed), removing it from the linked list.
# --hints--
You should create an `elif` statement that checks that `previous_node` is not `None`.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("remove").find_ifs()[0].find_conditions()[1]
assert _cond.is_equivalent("previous_node is not None")
`) })
```
You should assign `current_node.next` to `previous_node.next` inside the `elif` statement.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("remove").find_ifs()[0]
assert _cond.is_equivalent("if current_node is None:\\n return\\nelif previous_node is not None:\\n previous_node.next = current_node.next")
`) })
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
def remove(self, element):
previous_node = None
current_node = self.head
while current_node is not None and current_node.element != element:
previous_node = current_node
current_node = current_node.next
--fcc-editable-region--
if current_node is None:
return
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,73 @@
---
id: 688ace81e3fb5a95a1f04c55
title: Step 22
challengeType: 20
dashedName: step-22
---
# --description--
Next, create an `else` block that assigns `current_node.next` to `self.head`.
This handles the case where the element to be removed is found in the head node. By updating `self.head` to point to `current_node.next`, the head node is removed from the linked list.
# --hints--
You should create an `else` block that assigns `current_node.next` to `self.head`.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("remove").find_ifs()[0]
assert _cond.is_equivalent("if current_node is None:\\n return\\nelif previous_node is not None:\\n previous_node.next = current_node.next\\nelse:\\n self.head = current_node.next")
`) })
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
def remove(self, element):
previous_node = None
current_node = self.head
while current_node is not None and current_node.element != element:
previous_node = current_node
current_node = current_node.next
--fcc-editable-region--
if current_node is None:
return
elif previous_node is not None:
previous_node.next = current_node.next
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,78 @@
---
id: 688acfa518e1d19fdb55d9f3
title: Step 23
challengeType: 20
dashedName: step-23
---
# --description--
Next, at the end of the `remove` method, decrement `self.length` by 1. This decreases the length of the linked list to reflect the removal of a node.
# --hints--
You should decrement `self.length` by 1 at the end of the `remove` method.
```js
({
test: () =>
assert(
runPython(
`_Node(_code).find_class("LinkedList").find_function("remove").has_stmt("self.length -= 1")`
)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
def remove(self, element):
previous_node = None
current_node = self.head
while current_node is not None and current_node.element != element:
previous_node = current_node
current_node = current_node.next
if current_node is None:
return
elif previous_node is not None:
previous_node.next = current_node.next
else:
self.head = current_node.next
--fcc-editable-region--
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
```
@@ -0,0 +1,59 @@
---
id: 68b84df2648b4c96b25022f3
title: Step 8
challengeType: 20
dashedName: step-8
---
# --description--
Let's test your linked list so far! At the bottom of your code, create an instance of `LinkedList` called `my_list`. Then, using the `is_empty` method you created in the last step, print `my_list.is_empty()`.
# --hints--
You should create an instance of `LinkedList` called `my_list`.
```js
({
test: () => assert(
runPython(`
_Node(_code).find_variable("my_list").value_is_call("LinkedList")
`)
)
})
```
You should print `my_list.is_empty()`.
```js
({
test: () => assert(
runPython(`
_Node(_code).has_call("print(my_list.is_empty())")
`)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,95 @@
---
id: 68b9e951e4892721632acc26
title: Step 15
challengeType: 20
dashedName: step-15
---
# --description--
Great! Now let's test adding elements to your linked list. At the bottom of your code, after creating an instance of `LinkedList` called `my_list` and printing `my_list.is_empty()`, add `1` and `2` to the list using the `add` method.
Then, print `my_list.is_empty()` again to confirm that the list is no longer empty. Finally, print `my_list.length` to see the current length of the linked list.
# --hints--
You should add `1` to the list using the `add` method.
```js
({
test: () => assert(
runPython(`_Node(_code).has_call("my_list.add(1)")`)
)
})
```
You should add `2` to the list using the `add` method.
```js
({
test: () => assert(
runPython(`_Node(_code).has_call("my_list.add(2)")`)
)
})
```
You should print `my_list.is_empty()`.
```js
({
test: () => assert(
runPython(`
_Node(_code).find_calls("print")[1].is_equivalent("print(my_list.is_empty())")
`)
)
})
```
You should print `my_list.length`.
```js
({
test: () => assert(
runPython(`
_Node(_code).find_calls("print")[2].is_equivalent("print(my_list.length)")
`)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
current_node.next = node
self.length += 1
my_list = LinkedList()
print(my_list.is_empty())
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,144 @@
---
id: 68ba19dec78f654b7fca401e
title: Step 24
challengeType: 20
dashedName: step-24
---
# --description--
Now, let's test removing an element from your linked list. At the bottom of your code, remove `1` from the list using the `remove` method. Then, print `my_list.length` again to see the updated length of the linked list.
With that, the linked list data structure workshop is complete!
# --hints--
You should remove `1` from the list using the `remove` method.
```js
({
test: () => assert(
runPython(`_Node(_code).has_call("my_list.remove(1)")`)
)
})
```
You should print `my_list.length`.
```js
({
test: () => assert(
runPython(`
_Node(_code).find_calls("print")[3].is_equivalent("print(my_list.length)")
`)
)
})
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
self.length += 1
def remove(self, element):
previous_node = None
current_node = self.head
while current_node is not None and current_node.element != element:
previous_node = current_node
current_node = current_node.next
if current_node is None:
return
elif previous_node is not None:
previous_node.next = current_node.next
else:
self.head = current_node.next
self.length -= 1
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
--fcc-editable-region--
--fcc-editable-region--
```
# --solutions--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
current_node.next = node
self.length += 1
def remove(self, element):
previous_node = None
current_node = self.head
while current_node is not None and current_node.element != element:
previous_node = current_node
current_node = current_node.next
if current_node is None:
return
elif previous_node is not None:
previous_node.next = current_node.next
else:
self.head = current_node.next
self.length -= 1
my_list = LinkedList()
print(my_list.is_empty())
my_list.add(1)
my_list.add(2)
print(my_list.is_empty())
print(my_list.length)
my_list.remove(1)
print(my_list.length)
```
@@ -0,0 +1,63 @@
---
id: 68c0da2df8ce865dcf7769a7
title: Step 12
challengeType: 20
dashedName: step-12
---
# --description--
Still inside the `else` block, create a `while` loop that checks that `current_node.next` is not `None`.
Inside the `while` loop, assign `current_node.next` to `current_node`.
# --hints--
You should create a `while` loop that checks whether `current_node.next` is not `None`.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("add").find_ifs()[0].find_bodies()[1].find_whiles()[0].find_conditions()[0]
assert _cond.is_equivalent("current_node.next is not None")
`) })
```
You should assign `current_node.next` to `current_node` inside the `while` loop.
```js
({ test: () => runPython(`
_cond = _Node(_code).find_class("LinkedList").find_function("add").find_ifs()[0].find_bodies()[1].find_whiles()[0]
assert _cond.is_equivalent("while current_node.next is not None:\\n current_node = current_node.next")
`) })
```
# --seed--
## --seed-contents--
```py
class LinkedList:
class Node:
def __init__(self, element):
self.element = element
self.next = None
def __init__(self):
self.length = 0
self.head = None
def is_empty(self):
return self.length == 0
def add(self, element):
node = self.Node(element)
if self.is_empty():
self.head = node
--fcc-editable-region--
else:
current_node = self.head
--fcc-editable-region--
my_list = LinkedList()
print(my_list.is_empty())
```
@@ -0,0 +1,36 @@
{
"name": "Build a Linked List",
"isUpcomingChange": true,
"dashedName": "workshop-linked-list-class",
"helpCategory": "Python",
"usesMultifileEditor": true,
"hasEditableBoundaries": true,
"blockLayout": "challenge-grid",
"blockType": "workshop",
"challengeOrder": [
{ "id": "687d7deea6a2a22fa8816a73", "title": "Step 1" },
{ "id": "687d8c6f066877768f7ee441", "title": "Step 2" },
{ "id": "687d8e05a529a4838f1c961c", "title": "Step 3" },
{ "id": "688003f589b875af60273dd9", "title": "Step 4" },
{ "id": "687e344cc1993f7316af030c", "title": "Step 5" },
{ "id": "68800a64b06e80d9a31c131b", "title": "Step 6" },
{ "id": "687e366b3004a9831e4cbd41", "title": "Step 7" },
{ "id": "68b84df2648b4c96b25022f3", "title": "Step 8" },
{ "id": "68857e0a49baf4751f737a2a", "title": "Step 9" },
{ "id": "68858a1b4e867acd87f6f7e8", "title": "Step 10" },
{ "id": "688649c8673f842f49228a5e", "title": "Step 11" },
{ "id": "68c0da2df8ce865dcf7769a7", "title": "Step 12" },
{ "id": "68867c3898b09115d8c5140f", "title": "Step 13" },
{ "id": "68868f502659139bed8e5c90", "title": "Step 14" },
{ "id": "68b9e951e4892721632acc26", "title": "Step 15" },
{ "id": "6888d05ba074461b64f8eaca", "title": "Step 16" },
{ "id": "6888f9827637322d4f309192", "title": "Step 17" },
{ "id": "6888fe6c745b6852ed240229", "title": "Step 18" },
{ "id": "688ac1de985053329b4573d3", "title": "Step 19" },
{ "id": "688ac806194cfc60ba1e1767", "title": "Step 20" },
{ "id": "688acb2053ac7978a06345f1", "title": "Step 21" },
{ "id": "688ace81e3fb5a95a1f04c55", "title": "Step 22" },
{ "id": "688acfa518e1d19fdb55d9f3", "title": "Step 23" },
{ "id": "68ba19dec78f654b7fca401e", "title": "Step 24" }
]
}
@@ -733,6 +733,7 @@
"comingSoon": true,
"blocks": [
"lecture-working-with-common-data-structures",
"workshop-linked-list-class",
"lab-hash-table",
"review-data-structures",
"quiz-data-structures"