diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 487e57279e0..b48fa80ca78 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -5600,6 +5600,13 @@ "Learn about common data structures and how to work with them in JavaScript." ] }, + "workshop-linked-list-js": { + "title": "Build a Linked List", + "intro": [ + "In the previous lessons, you learned about some common data structures.", + "In this workshop, you will build a linked list using JavaScript." + ] + }, "lab-linked-list-operations": { "title": "Implement Linked List Operations", "intro": [ diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00a051b9a18694d00c16b.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00a051b9a18694d00c16b.md new file mode 100644 index 00000000000..ea343c0fb46 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00a051b9a18694d00c16b.md @@ -0,0 +1,50 @@ +--- +id: 69a00a051b9a18694d00c16b +title: Step 1 +challengeType: 1 +dashedName: step-1 +--- + +# --description-- + +In this workshop, you'll implement a linked list. + +To begin, create a function named `initList`. Inside it, return an object with a `head` property set to `null`, and a `length` property of `0`. + +This is the function you will call to initialize a linked list. The `head` represents the first element in the list, initially, it is `null` because there's no element in the list. The `length` tracks the number of nodes (elements) in the list, which you will increment or decrement when adding or removing a node from the list. + +# --hints-- + +You should create an `initList` function. + +```js +assert.isFunction(initList) +``` + +Your `initList` function should return an object. + +```js +assert.isObject(initList()); +``` + +Your `initList` function should return an object with a `head` set to `null`. + +```js +assert.propertyVal(initList(), "head", null); +``` + +Your `initList` function should return an object with a `length` set to `0`. + +```js +assert.propertyVal(initList(), "length", 0); +``` + +# --seed-- + +## --seed-contents-- + +```js +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00cd4ec513345d40e95ec.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00cd4ec513345d40e95ec.md new file mode 100644 index 00000000000..76aebdf467f --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00cd4ec513345d40e95ec.md @@ -0,0 +1,54 @@ +--- +id: 69a00cd4ec513345d40e95ec +title: Step 2 +challengeType: 1 +dashedName: step-2 +--- + +# --description-- + +The next thing you will work on is a function that lets you check if the list is empty. + +To do that, create a function named `isEmpty` that takes a `list` parameter. Inside the function, return a check to see if the `length` property of `list` is strictly equal to `0`. + +# --hints-- + +You should create an `isEmpty` function. + +```js +assert.isFunction(isEmpty) +``` + +Your `isEmpty` function should have a `list` parameter. + +```js +const isEmptyParams = __helpers.getFunctionParams(isEmpty.toString()); +assert.deepEqual(isEmptyParams[0].name, "list"); +``` + +Your `isEmpty` function should return `list.length === 0`. + +```js +const emptyList = { head: null, length: 0 }; +const nonEmptyList = { head: {}, length: 1 }; + +assert.isTrue(isEmpty(emptyList)); +assert.isFalse(isEmpty(nonEmptyList)); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00eaa43458e618331873c.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00eaa43458e618331873c.md new file mode 100644 index 00000000000..09c64797567 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00eaa43458e618331873c.md @@ -0,0 +1,50 @@ +--- +id: 69a00eaa43458e618331873c +title: Step 3 +challengeType: 1 +dashedName: step-3 +--- + +# --description-- + +Now you will work on the function that will add a node to the list. + +Create an `add` function with `list` and `element` parameters. + +# --hints-- + +You should create an `add` function. + +```js +assert.isFunction(add) +``` + +Your `add` function should have `list` and `element` parameters. + +```js +const addParams = __helpers.getFunctionParams(add.toString()); +const addParamsNames = addParams.map(param => param.name) +assert.include(addParamsNames, "list"); +assert.include(addParamsNames, "element"); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00f673f171e29159e3ad8.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00f673f171e29159e3ad8.md new file mode 100644 index 00000000000..6db0c382211 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a00f673f171e29159e3ad8.md @@ -0,0 +1,55 @@ +--- +id: 69a00f673f171e29159e3ad8 +title: Step 4 +challengeType: 1 +dashedName: step-4 +--- + +# --description-- + +This node would need two properties, the element to add, and a pointer to the next node. + +Inside the add function, create an object named `node`, it should have a property named `element`, and a `next` property set to `null`, which is the pointer to the next element of the list. + +# --hints-- + +You should create an object named `node` inside your `add` function. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /const|var|let\s+node\s*=\s*{/); +``` + +Your `node` object should have a property named `element` set to `element`. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /element\s*:\s*element/); +``` + +Your `node` object should have a property named `next` set to `null`. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /next\s*:\s*null/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + --fcc-editable-region-- + + --fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a0102e761a245bb1cbd8e7.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a0102e761a245bb1cbd8e7.md new file mode 100644 index 00000000000..de68a8931d9 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a0102e761a245bb1cbd8e7.md @@ -0,0 +1,73 @@ +--- +id: 69a0102e761a245bb1cbd8e7 +title: Step 5 +challengeType: 1 +dashedName: step-5 +--- + +# --description-- + +At this point, you should test the linked list for better understanding. + +Create a `myList` variable and set it to `initList()`. Under it, log a call of `isEmpty()` using `myList` as the parameter to the console. Then, after that, call `add` with `myList` and a number of your choice, then log `myList` to the console. Under that, log another call of `isEmpty()` to the console using `myList` as the parameter again. + +# --hints-- + +You should create a `myList` variable set to `initList()`. + +```js +assert.deepEqual(myList, initList()); +``` + +You should log a call to `isEmpty(myList)` to the console. + +```js +assert.match(__helpers.removeJSComments(code), /console\.log\(isEmpty\(myList\)\)/) +``` + +You should call `add` with `myList` and a number of your choice as the parameters. + +```js +assert.match(__helpers.removeJSComments(code), /add\s*\(\s*myList\s*,\s*\d+\s*\)/); +``` + +You should log your `myList` variable to the console. + +```js +assert.match(__helpers.removeJSComments(code), /console\.log\(myList\)/) +``` + +You should log `isEmpty(myList)` to the console again. + +```js +assert.match(__helpers.removeJSComments(code), /console\.log\(myList\)\s*console\.log\(isEmpty\(myList\)\)/) +``` + + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; +} + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a012c6224fac85832247dd.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a012c6224fac85832247dd.md new file mode 100644 index 00000000000..b78e4d9e033 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a012c6224fac85832247dd.md @@ -0,0 +1,60 @@ +--- +id: 69a012c6224fac85832247dd +title: Step 6 +challengeType: 1 +dashedName: step-6 +--- + +# --description-- + +Notice the `true`, `{ head: null, length: 0 }`, and `true` results in the console? This happens because you've not assigned anything to the list `myList`, and you've not incremented the `length` property. + +Go ahead and assign `node` to `list.head`, and under that, increment the `length` property of `list`. + +# --hints-- + +You should assign `node` to `list.head`. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /list\.head\s*=\s*node;?/); +``` + +You should increment the `length` property of `list`. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /list\.length\+\+;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + --fcc-editable-region-- + + --fcc-editable-region-- +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a013a86c97dac3784b2636.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a013a86c97dac3784b2636.md new file mode 100644 index 00000000000..eccd726611a --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a013a86c97dac3784b2636.md @@ -0,0 +1,63 @@ +--- +id: 69a013a86c97dac3784b2636 +title: Step 7 +challengeType: 1 +dashedName: step-7 +--- + +# --description-- + +Now, the log should show something like `{ head: { element: 42, next: null }, length: 1 }` in the console. + +However, this is not how you would handle a case where the added node is the first element in the list, that is, the head. + +To do that properly, use an if statement to check if the list is empty by calling the `isEmpty` function with the `list`. If that's true, then move your `list.head = node` line into the body of the `if` statement. + +# --hints-- + +You should have an `if` statement with the condition `isEmpty(list)`. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /if\s*\(isEmpty\(list\)\)\s*\{\s*/); +``` + +You should move your `list.head = node` line into the `if` statement. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /if\s*\(isEmpty\(list\)\)\s*\{\s*list\.head\s*=\s*node;?\s*\}/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + +--fcc-editable-region-- + list.head = node; +--fcc-editable-region-- + list.length++; +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a014bd9b1730e94136279f.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a014bd9b1730e94136279f.md new file mode 100644 index 00000000000..b3ded076fa9 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a014bd9b1730e94136279f.md @@ -0,0 +1,64 @@ +--- +id: 69a014bd9b1730e94136279f +title: Step 8 +challengeType: 1 +dashedName: step-8 +--- + +# --description-- + +If the list is not empty, then you want to find its end, add the new element there, and make it point to `null`. This means you have to loop through the list from the `head`. + +To start that, open up an `else` clause. Inside it, use `let` to create a `current` variable and set it to `list.head`. + +# --hints-- + +You should have an `else` clause. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /else\s*{/); +``` + +You should create a `current` variable set to `list.head` inside the `else` clause. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /else\s*{\s*let|var\s+current\s*=\s*list\.head;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + --fcc-editable-region-- + } + --fcc-editable-region-- + + list.length++; +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a016ac6edea7d8c8020c98.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a016ac6edea7d8c8020c98.md new file mode 100644 index 00000000000..f5f2430be3b --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a016ac6edea7d8c8020c98.md @@ -0,0 +1,59 @@ +--- +id: 69a016ac6edea7d8c8020c98 +title: Step 9 +challengeType: 1 +dashedName: step-9 +--- + +# --description-- + +Now, create a `while` loop with `current.next !== null` as the condition. This means the loop should keep running as long as the current node has another node after it. + +# --hints-- + +You should create a `while` loop with the condition `current.next !== null`. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /while\s+\(current\.next\s*!==\s*null\)\s*\{\s*/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + --fcc-editable-region-- + + --fcc-editable-region-- + } + + list.length++; +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a0179a85b00b6127e0af45.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a0179a85b00b6127e0af45.md new file mode 100644 index 00000000000..44aa1f66e29 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a0179a85b00b6127e0af45.md @@ -0,0 +1,61 @@ +--- +id: 69a0179a85b00b6127e0af45 +title: Step 10 +challengeType: 1 +dashedName: step-10 +--- + +# --description-- + +Inside the `while` loop, update `current` to `current.next` so the loop moves forward through the list one node at a time, and stops when it reaches the node with a `next` property of `null`, that is, the end of the list. + +# --hints-- + +You should update the value of your `current` variable to `current.next` inside the `while` loop. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /current\s*=\s*current\.next;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + --fcc-editable-region-- + + --fcc-editable-region-- + } + } + + list.length++; +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a01864d343dc2f2484d131.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a01864d343dc2f2484d131.md new file mode 100644 index 00000000000..418e1b49968 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a01864d343dc2f2484d131.md @@ -0,0 +1,62 @@ +--- +id: 69a01864d343dc2f2484d131 +title: Step 11 +challengeType: 1 +dashedName: step-11 +--- + +# --description-- + +After finding the last node, you need to attach the new node to it. To do that, set `current.next` to `node` under the while loop but still within the `else` clause. + +# --hints-- + +You should set `current.next` to `node` under your `while` loop. + +```js +assert.match(__helpers.removeJSComments(add.toString()), /current\.next\s*=\s*node;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + --fcc-editable-region-- + + --fcc-editable-region-- + } + + list.length++; +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a02ee82bbeaee00e44c67d.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a02ee82bbeaee00e44c67d.md new file mode 100644 index 00000000000..d70565bc0cf --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a02ee82bbeaee00e44c67d.md @@ -0,0 +1,65 @@ +--- +id: 69a02ee82bbeaee00e44c67d +title: Step 12 +challengeType: 1 +dashedName: step-12 +--- + +# --description-- + +That's all you need to add an element to the list. To see what things look like, add two more numbers of your choice to the `myList` list. + +# --hints-- + +You should add two more numbers of your choice to the `myList` list. + +```js +const matches = __helpers.removeJSComments(code).match(/add\s*\(\s*myList\s*,\s*\d+\s*\);?/g) || []; + +assert.isAtLeast(matches.length, 3); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +--fcc-editable-region-- + +--fcc-editable-region-- +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a030fbe487f185f55b8627.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a030fbe487f185f55b8627.md new file mode 100644 index 00000000000..101dbcba5f1 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a030fbe487f185f55b8627.md @@ -0,0 +1,77 @@ +--- +id: 69a030fbe487f185f55b8627 +title: Step 13 +challengeType: 1 +dashedName: step-13 +--- + +# --description-- + +Now, you will work on a function to remove a node from the list. + +Create a `remove` function with `list` and `element` parameters. + +# --hints-- + +You should create a `remove` function. + +```js +assert.isFunction(remove) +``` + +Your `remove` function should have `list` and `element` parameters. + +```js +const removeParams = __helpers.getFunctionParams(remove.toString()); +const removeParamsNames = removeParams.map(param => param.name) +assert.include(removeParamsNames, "list"); +assert.include(removeParamsNames, "element"); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +--fcc-editable-region-- + +--fcc-editable-region-- + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03aaa1e6fe8152788ce6a.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03aaa1e6fe8152788ce6a.md new file mode 100644 index 00000000000..3b11d24abc9 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03aaa1e6fe8152788ce6a.md @@ -0,0 +1,78 @@ +--- +id: 69a03aaa1e6fe8152788ce6a +title: Step 14 +challengeType: 1 +dashedName: step-14 +--- + +# --description-- + +Inside the `remove` function, use `let` to create a `previous` variable set to `null`, and `let` again to create a `current` variable set to `list.head`. These are the variables you will use in the loop that will traverse the list. + +`current` tracks the node currently being checked in the list, starting at the head and moving forward one node at a time. `previous`, on the other hand, keeps track of the node right before the current one. + +This is important when removing a node because you must update the next value of the previous node so it points to the node after the one being removed, in order to keep the list connected. + +# --hints-- + +You should use `let` to create a `previous` variable set to `null` inside your `remove` function. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /let|var\s+previous\s*=\s*null;?/); +``` + +You should use `let` to create a `current` variable set to `list.head` inside your `remove` function. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /let|var\s+current\s*=\s*list\.head;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + --fcc-editable-region-- + + --fcc-editable-region-- +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03ddce82b0626f329b001.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03ddce82b0626f329b001.md new file mode 100644 index 00000000000..4ef6b3c06ec --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03ddce82b0626f329b001.md @@ -0,0 +1,73 @@ +--- +id: 69a03ddce82b0626f329b001 +title: Step 15 +challengeType: 1 +dashedName: step-15 +--- + +# --description-- + +Now, create a `while` loop that checks if `current` is not strictly `null` and `current.element` is not strictly equal to element. + +This means the loop should continue traversing the list until the end of the list is reached or the element to remove is found. + +# --hints-- + +You should create a `while` loop with the condition `current !== null && current.element !== element`. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /while\s+\(current\s*!==\s*null\s*&&\s*current\.element\s*!==\s*element\)\s*\{\s*/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + --fcc-editable-region-- + + --fcc-editable-region-- +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03f70b50b4c4d9a0f0113.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03f70b50b4c4d9a0f0113.md new file mode 100644 index 00000000000..2df1106959d --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a03f70b50b4c4d9a0f0113.md @@ -0,0 +1,79 @@ +--- +id: 69a03f70b50b4c4d9a0f0113 +title: Step 16 +challengeType: 1 +dashedName: step-16 +--- + +# --description-- + +Inside the loop, reassign `previous` to `current`, and `current` to `current.next`. This means `current` checks the next node, and `previous` always stays one node behind. + +# --hints-- + +You should reassign the `previous` variable to `current`. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /previous\s*=\s*current;?/); +``` + +You should reassign the `current` variable to `current.next`. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /current\s*=\s*current\.next;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + while (current !== null && current.element !== element) { + --fcc-editable-region-- + + --fcc-editable-region-- + } +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04088e600bd8074a9852f.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04088e600bd8074a9852f.md new file mode 100644 index 00000000000..27f7e4024b5 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04088e600bd8074a9852f.md @@ -0,0 +1,83 @@ +--- +id: 69a04088e600bd8074a9852f +title: Step 17 +challengeType: 1 +dashedName: step-17 +--- + +# --description-- + +If `current` is `null`, it means that's the end of the list, so the function should stop running. + +Create an `if` statement that checks if `current` is strictly equal to `null`. Inside the `if` statement, use `return` to exit the function. + +# --hints-- + +You should create an `if` statement with the condition `current === null`. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /if\s*\(current\s*===\s*null\s*\)\s*\{\s*/); +``` + +You should use the `return` keyword inside your `if` statement. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /if\s*\(current\s*===\s*null\s*\)\s*\{\s*return;?\s*\}/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + while (current !== null && current.element !== element) { + previous = current; + current = current.next; + } + --fcc-editable-region-- + + --fcc-editable-region-- +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04466917c66b132323a1b.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04466917c66b132323a1b.md new file mode 100644 index 00000000000..968bd95456d --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04466917c66b132323a1b.md @@ -0,0 +1,87 @@ +--- +id: 69a04466917c66b132323a1b +title: Step 18 +challengeType: 1 +dashedName: step-18 +--- + +# --description-- + +If `previous` is not `null`, this means the element to be removed is not at the head but somewhere within the list, so the current node should be bypassed by linking the previous node directly to the next node. + +To do that, create another `if` statement that checks if previous is strictly not `null`. If that's the case, set `previous.next` to `current.next`. + +# --hints-- + +You should create another `if` statement with the condition `previous !== null`. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /if\s*\(previous\s*!==\s*null\s*\)\s*\{\s*/); +``` + +You should set `previous.next` to `current.next`. + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /if\s*\(previous\s*!==\s*null\s*\)\s*\{\s*previous\.next\s*=\s*current\.next;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + while (current !== null && current.element !== element) { + previous = current; + current = current.next; + } + + if (current === null) { + return; + } +--fcc-editable-region-- + +--fcc-editable-region-- +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a045fd236d0d973a59f103.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a045fd236d0d973a59f103.md new file mode 100644 index 00000000000..dfe7d2f90f5 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a045fd236d0d973a59f103.md @@ -0,0 +1,91 @@ +--- +id: 69a045fd236d0d973a59f103 +title: Step 19 +challengeType: 1 +dashedName: step-19 +--- + +# --description-- + +If `previous` is `null`, this means the element to be removed is at the head of the list, so you should update the `head` to point to the next node in order to remove the first element. + +To do that, add an `else` clause. Inside it, set `list.head` to `current.next`. + +# --hints-- + +You should add an `else` clause to your `if` statement. + +```js +assert.match(__helpers.removeJSComments(remove.toString().split("previous.next = current.next;")), /\}\s*else\s*\{\s*/); +``` + +You should set `list.head` to `current.next` inside the `else` clause. + +```js +assert.match(__helpers.removeJSComments(remove.toString().split("previous.next = current.next;")), /\}\s*else\s*\{\s*list\.head\s*=\s*current\.next;?/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + while (current !== null && current.element !== element) { + previous = current; + current = current.next; + } + + if (current === null) { + return; + } + + if(previous !== null) { + previous.next = current.next; + --fcc-editable-region-- + } + + --fcc-editable-region-- +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a046a1a74385bb4be1bb88.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a046a1a74385bb4be1bb88.md new file mode 100644 index 00000000000..627dab20378 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a046a1a74385bb4be1bb88.md @@ -0,0 +1,86 @@ +--- +id: 69a046a1a74385bb4be1bb88 +title: Step 20 +challengeType: 1 +dashedName: step-20 +--- + +# --description-- + +Now, you need to decrement `length` in the `remove` function to keep track of the actual number of elements remaining in the list after removing one. + +# --hints-- + +You should decrement the `length` property of `list` using the decrement operator (`--`). + +```js +assert.match(__helpers.removeJSComments(remove.toString()), /list.length\-\-/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + while (current !== null && current.element !== element) { + previous = current; + current = current.next; + } + + if (current === null) { + return; + } + + if(previous !== null) { + previous.next = current.next; + } else { + list.head = current.next; + } + + --fcc-editable-region-- + + --fcc-editable-region-- +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +``` diff --git a/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04712866a37ea8f38b6bd.md b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04712866a37ea8f38b6bd.md new file mode 100644 index 00000000000..c8ffbe3c1c6 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-linked-list-js/69a04712866a37ea8f38b6bd.md @@ -0,0 +1,165 @@ +--- +id: 69a04712866a37ea8f38b6bd +title: Step 21 +challengeType: 1 +dashedName: step-21 +--- + +# --description-- + +Now, you should test out the `remove` function. + +Remove any of the numbers from the list by calling the `remove` function with `myList` and the number to remove, then log `myList` to the console using `console.log(JSON.stringify(myList, null, 2))` to see the complete updated list. + +With that, your linked list workshop is complete! + +# --hints-- + +You should remove any of the existing numbers using the `remove` function. + +```js +assert.match(__helpers.removeJSComments(code),/remove\s*\(\s*myList\s*,\s*(42|43|44)\s*\)/); +``` + +You should log `myList` to the console again, this time using `JSON.stringify(myList, null, 2)`. + +```js +assert.match(__helpers.removeJSComments(code), /console\.log\s*\(\s*JSON\.stringify\s*\(\s*myList\s*,\s*null\s*,\s*2\s*\)\s*\)/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + while (current !== null && current.element !== element) { + previous = current; + current = current.next; + } + + if (current === null) { + return; + } + + if(previous !== null) { + previous.next = current.next; + } else { + list.head = current.next; + } + + list.length--; + +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +--fcc-editable-region-- + +--fcc-editable-region-- +``` + +# --solutions-- + +```js +function initList() { + return { + head: null, + length: 0 + }; +} + +function isEmpty(list) { + return list.length === 0; +} + +function add(list, element) { + const node = { + element: element, + next: null + }; + + if (isEmpty(list)) { + list.head = node; + } else { + let current = list.head; + while (current.next !== null) { + current = current.next; + } + current.next = node; + } + + list.length++; +} + +function remove(list, element) { + let previous = null; + let current = list.head; + + while (current !== null && current.element !== element) { + previous = current; + current = current.next; + } + + if (current === null) { + return; + } + + if(previous !== null) { + previous.next = current.next; + } else { + list.head = current.next; + } + + list.length--; + +} + +const myList = initList(); +console.log(isEmpty(myList)) +add(myList, 42); +add(myList, 43); +add(myList, 44); +console.log(myList) +console.log(isEmpty(myList)) +remove(myList, 43); +console.log(JSON.stringify(myList, null, 2)) +``` diff --git a/curriculum/structure/blocks/workshop-linked-list-js.json b/curriculum/structure/blocks/workshop-linked-list-js.json new file mode 100644 index 00000000000..e131dfe080b --- /dev/null +++ b/curriculum/structure/blocks/workshop-linked-list-js.json @@ -0,0 +1,32 @@ +{ + "isUpcomingChange": true, + "dashedName": "workshop-linked-list-js", + "helpCategory": "JavaScript", + "blockLayout": "challenge-grid", + "blockLabel": "workshop", + "usesMultifileEditor": true, + "hasEditableBoundaries": true, + "challengeOrder": [ + { "id": "69a00a051b9a18694d00c16b", "title": "Step 1" }, + { "id": "69a00cd4ec513345d40e95ec", "title": "Step 2" }, + { "id": "69a00eaa43458e618331873c", "title": "Step 3" }, + { "id": "69a00f673f171e29159e3ad8", "title": "Step 4" }, + { "id": "69a0102e761a245bb1cbd8e7", "title": "Step 5" }, + { "id": "69a012c6224fac85832247dd", "title": "Step 6" }, + { "id": "69a013a86c97dac3784b2636", "title": "Step 7" }, + { "id": "69a014bd9b1730e94136279f", "title": "Step 8" }, + { "id": "69a016ac6edea7d8c8020c98", "title": "Step 9" }, + { "id": "69a0179a85b00b6127e0af45", "title": "Step 10" }, + { "id": "69a01864d343dc2f2484d131", "title": "Step 11" }, + { "id": "69a02ee82bbeaee00e44c67d", "title": "Step 12" }, + { "id": "69a030fbe487f185f55b8627", "title": "Step 13" }, + { "id": "69a03aaa1e6fe8152788ce6a", "title": "Step 14" }, + { "id": "69a03ddce82b0626f329b001", "title": "Step 15" }, + { "id": "69a03f70b50b4c4d9a0f0113", "title": "Step 16" }, + { "id": "69a04088e600bd8074a9852f", "title": "Step 17" }, + { "id": "69a04466917c66b132323a1b", "title": "Step 18" }, + { "id": "69a045fd236d0d973a59f103", "title": "Step 19" }, + { "id": "69a046a1a74385bb4be1bb88", "title": "Step 20" }, + { "id": "69a04712866a37ea8f38b6bd", "title": "Step 21" } + ] +} diff --git a/curriculum/structure/superblocks/javascript-v9.json b/curriculum/structure/superblocks/javascript-v9.json index eab9b8d2447..f0ed21caf98 100644 --- a/curriculum/structure/superblocks/javascript-v9.json +++ b/curriculum/structure/superblocks/javascript-v9.json @@ -303,6 +303,7 @@ "comingSoon": true, "blocks": [ "lecture-working-with-common-data-structures-js", + "workshop-linked-list-js", "lab-linked-list-operations", "lab-implement-a-stack", "lab-implement-a-queue",