diff --git a/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures.json b/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures.json
index 4aef953351..ac59ef8ab6 100644
--- a/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures.json
+++ b/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures.json
@@ -5,17 +5,58 @@
"helpRoom": "Help",
"challenges": [
{
- "id": "587d7b7e367417b2b2512b20",
- "title": "Use an array to store a collection of data",
+ "id": "587d7dac367417b2b2516zx5",
+ "title": "Introduction to Arrays",
"description": [
- "Arrays are JavaScript's most fundamental, and perhaps most common, data structure. An array is simply a collection of data, of any length, arranged in a comma separated list and enclosed in brackets [ ]
. While we often make the distinction in JavaScript between Objects and Arrays, it is important to note that technically, an array is a type of object.",
- "Arrays can store any type of data supported by JavaScript, and while they are a simple and basic form of data structure, they can also be very complex and powerful - all of which depends on how the programmer utilizes them.",
- "The below is an example of a valid array, notice it contains booleans, strings, numbers, objects, and other arrays (this is called a nested, or multi-dimensional array), among other valid data types:",
- "
let ourArray = [undefined, null, false, 'one', 2, {'three': 4}, [5, 'six']];", - "Note that all array's have a length property, which as shown above, can be very easily accessed with the syntax
console.log(ourArray.length);
// logs 7
Array.length
.",
- "JavaScript offers many built in methods which allow us to access, traverse, and mutate arrays as needed, depending on our purpose. In the coming challenges, we will discuss several of the most common and useful methods, and a few other key techniques, that will help us to better understand and utilize arrays as data structures in JavaScript.",
+ [
+ "",
+ "",
+ "Arrays are one of JavaScript's most fundamental built-in data structures, and probably the data structure that you will work with most often throughout the course of the freeCodeCamp curriculum. The array is by no means unique to JavaScript, however — in fact, it’s probably safe to say that arrays are utilized by almost every complex program... ever.[element1, element2, element3]
. They can be any length, and store any type of data supported by JavaScript.let simpleArray = ['one', 2, 'three’, true, false, undefined, null];", + "All array's have a length property, which as shown above, can be very easily accessed with the syntax
console.log(simpleArray.length);
// logs 7
Array.length
.",
+ "A more complex implementation of an array can be seen below. This is known as a multi-dimensional array, or an array that contains other arrays. Notice that this array also contains JavaScript objects, which we will examine very closely in our next section, but for now, all you need to know is that arrays are also capable of storing complex objects.",
+ "let complexArray = [", "
[
{
one: 1,
two: 2
},
{
three: 3,
four: 4
}
],
[
{
a: \"a\",
b: \"b\"
},
{
c: \"c\",
d: “d”
}
]
];
yourArray
. Complete the declaration by defining an array of at least 5 elements in length. Your array should contain at least one string, one number, and one boolean."
+ "We have defined a variable called yourArray
. Complete the statement by assigning an array of at least 5 elements in length to the yourArray
variable. Your array should contain at least one string, one number, and one boolean."
],
"challengeSeed": [
"let yourArray; // change this line"
@@ -41,7 +82,7 @@
"let ourArray = [\"a\", \"b\", \"c\"];", "In an array, each array item has an index. This index doubles as the position of that item in the array, and how you reference it. However, it is important to note, that JavaScript arrays are zero-indexed, meaning that the first element of an array is actually at the zeroth position, not the first.", "In order to retrieve an element from an array we can enclose an index in brackets and append it to the end of an array, or more commonly, to a variable which references an array object. This is known as bracket notation.", - "For example, if we want to get the
\"a\"
from ourArray
and assign it to a variable, we can do so with the following code:",
+ "For example, if we want to retrieve the \"a\"
from ourArray
and assign it to a variable, we can do so with the following code:",
"let ourVariable = ourArray[0];", "In addition to accessing the value associated with an index, you can also set an index to a value using the same notation:", "
// ourVariable equals \"a\"
ourArray[1] = \"not b anymore\";", @@ -136,7 +177,7 @@ "title": "Remove Items Using splice()", "description": [ "Ok, so we've learned how to remove elements from the beginning and end of arrays using
// ourArray now equals [\"a\", \"not b anymore\", \"c\"];
pop()
and shift()
, but what if we want to remove an element from somewhere in the middle? Or remove more than one element at once? Well, that's where splice()
comes in. splice()
allows us to do just that: remove any number of consecutive elements from anywhere on an array.",
- "splice()
can take up to 3 parameters, but for now, we'll focus on just the first 2. The first two parameters of splice()
are integers which represent indexes, or postions, of the array that splice()
is being called upon. And remember, arrays are zero-indexed, so to indicate the first element of an array, we would use 0
. splice()
's first parameter represents the index on the array from which to begin removing elements, while the second parameter indicates the number of elements to delete. For example:",
+ "splice()
can take up to 3 parameters, but for now, we'll focus on just the first 2. The first two parameters of splice()
are integers which represent indexes, or positions, of the array that splice()
is being called upon. And remember, arrays are zero-indexed, so to indicate the first element of an array, we would use 0
. splice()
's first parameter represents the index on the array from which to begin removing elements, while the second parameter indicates the number of elements to delete. For example:",
"let array = ['today', 'was', 'not', 'so', 'great'];", "
array.splice(2, 2);
// remove 2 elements beginning with the 3rd element
// array now equals ['today', 'was', 'great']
splice()
not only modifies the array it's being called on, but it also returns a new array containing the value of the removed elements:",
"let array = ['I', 'am', 'feeling', 'really', 'happy'];", @@ -197,7 +238,7 @@ "id": "587d7b7a367417b2b2512b12", "title": "Copy an Array with slice()", "description": [ - "The next method we will cover is
let newArray = array.splice(3, 2);
// newArray equals ['really', 'happy']
slice()
. slice()
, rather than modifying an array, copies, or extracts, a given mumber of elements to a new array, leaving the array it is called upon untouched. slice()
takes only 2 parameters — the first is the index at which to begin extraction, and the second is the index at which to stop extraction (extraction will occur up to, but not including the element at this index). Consider this:",
+ "The next method we will cover is slice()
. slice()
, rather than modifying an array, copies, or extracts, a given number of elements to a new array, leaving the array it is called upon untouched. slice()
takes only 2 parameters — the first is the index at which to begin extraction, and the second is the index at which to stop extraction (extraction will occur up to, but not including the element at this index). Consider this:",
"let weatherConditions = ['rain', 'snow', 'sleet', 'hail', 'clear'];", "In effect, we have created a new array by extracting elements from an existing array.", "
let todaysWeather = weatherConditions.slice(1, 3);
// todaysWeather equals ['snow', 'sleet'];
// weatherConditions still equals ['rain', 'snow', 'sleet', 'hail', 'clear']
slice()
allows us to be selective about what elements of an array to copy, ammong several other useful tasks, ES6's new spread operator allows us to easily copy all of an array's elements, in order, with a simple and highly readable syntax. The spread syntax simply looks like this: ...
",
+ "While slice()
allows us to be selective about what elements of an array to copy, among several other useful tasks, ES6's new spread operator allows us to easily copy all of an array's elements, in order, with a simple and highly readable syntax. The spread syntax simply looks like this: ...
",
"In practice, we can use the spread operator to copy an array like so:",
"let thisArray = [true, true, undefined, false, null];", "
let thatArray = [...thisArray];
// thatArray equals [true, true, undefined, false, null]
// thisArray remains unchanged, and is identical to thatArray
copyMachine
which takes arr
(an array) and num
(a number) as arguments. The function is supposed to return a new array made up of num
copies of arr
. We have done most of the work for you, but it doesn't work quite right yet. Modidy the function using spread syntax so that it works correctly (hint: another method we have already covered might come in handy here!)."
+ "We have defined a function, copyMachine
which takes arr
(an array) and num
(a number) as arguments. The function is supposed to return a new array made up of num
copies of arr
. We have done most of the work for you, but it doesn't work quite right yet. Modify the function using spread syntax so that it works correctly (hint: another method we have already covered might come in handy here!)."
],
"challengeSeed": [
"function copyMachine(arr, num) {",
@@ -264,7 +305,7 @@
"title": "Combine Arrays with the Spread Operator",
"description": [
"Another huge advantage of the spread operator, is the ability to combine arrays, or to insert all the elements of one array into another, at any index. With more traditional syntaxes, we can concatenate arrays, but this only allows us to combine arrays at the end of one, and at the start of another. Spread syntax makes the following operation extremely simple:",
- "let thisArray = ['sage', 'rosemary', 'parsely', 'thyme'];", + "
let thatArray = ['basil', 'cilantro', ...thisArray, 'corriander'];
// thatArray now equals ['basil', 'cilantro', 'sage', 'rosemary', 'parsely', 'thyme', 'corriander']
let thisArray = ['sage', 'rosemary', 'parsley', 'thyme'];", "Using spread syntax, we have just achieved an operation that would have been more more complex and more verbose had we used traditional methods.", "
let thatArray = ['basil', 'cilantro', ...thisArray, 'coriander'];
// thatArray now equals ['basil', 'cilantro', 'sage', 'rosemary', 'parsley', 'thyme', 'coriander']
spreadOut
that returns the variable sentence
, modify the function using the spread operator so that it returns the array ['learning', 'to', 'code', 'is', 'fun']
."
@@ -332,7 +373,7 @@
"We have defined a function, filteredArray
, which takes arr
, a nested array, and elem
as arguments, and returns a new array. elem
represents an element that may or may not be present on one or more of the arrays nested within arr
. Modify the function, using a for
loop, to return a filtered version of the passed array such that any array nested within arr
containing elem
has been removed."
],
"challengeSeed": [
- "function filteredArray(arr, num) {",
+ "function filteredArray(arr, elem) {",
" let newArr = [];",
" // change code below this line",
"",
@@ -345,7 +386,7 @@
],
"tests": [
"assert.deepEqual(filteredArray([ [10, 8, 3], [14, 6, 23], [3, 18, 6] ], 18), [[10, 8, 3], [14, 6, 23]], 'message: filteredArray([[10, 8, 3], [14, 6, 23], [3, 18, 6]], 18)
should return [ [10, 8, 3], [14, 6, 23] ]
');",
- "assert.deepEqual(filteredArray([ ['trumpets', 2], ['flutes', 4], ['saxaphones', 2] ], 2), [['flutes', 4]], 'message: filteredArray([ [\"trumpets\", 2], [\"flutes\", 4], [\"saxaphones\"], 2], 2)
should return [ [\"flutes\", 4] ]
');",
+ "assert.deepEqual(filteredArray([ ['trumpets', 2], ['flutes', 4], ['saxophones', 2] ], 2), [['flutes', 4]], 'message: filteredArray([ [\"trumpets\", 2], [\"flutes\", 4], [\"saxophones\"], 2], 2)
should return [ [\"flutes\", 4] ]
');",
"assert.deepEqual(filteredArray([['amy', 'beth', 'sam'], ['dave', 'sean', 'peter']], 'peter'), [['amy', 'beth', 'sam']], 'message: filteredArray([ [\"amy\", \"beth\", \"sam\"], [\"dave\", \"sean\", \"peter\"] ], \"peter\")
should return [ [\"amy\", \"beth\", \"sam\"] ]
');",
"assert.deepEqual(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3), [], 'message: filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3)
should return [ ]
');",
"assert.notStrictEqual(filteredArray.toString().search(/for/), -1, 'message: The filteredArray
function should utilize a for
loop');"
@@ -384,28 +425,74 @@
"tests": [
"assert.strictEqual((function(arr) { let flattened = (function flatten(arr) { const flat = [].concat(...arr); return flat.some (Array.isArray) ? flatten(flat) : flat; })(arr); for (let i = 0; i < flattened.length; i++) { if ( typeof flattened[i] !== 'number' && typeof flattened[i] !== 'string' && typeof flattened[i] !== 'boolean') { return false } } return true })(myNestedArray), true, 'message: myNestedArray
should contain only numbers, booleans, and strings as data elements');",
"assert.strictEqual((function(arr) {let depth = 0;function arrayDepth(array, i, d) { if (Array.isArray(array[i])) { arrayDepth(array[i], 0, d + 1);} else { depth = (d > depth) ? d : depth;}if (i < array.length) { arrayDepth(array, i + 1, d);} }arrayDepth(arr, 0, 0);return depth;})(myNestedArray), 4, 'message: myNestedArray
should have exactly 5 levels of depth');",
- "assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deep').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deep')[0] === 2, 'message: myNestedArray
should contain exactly one occurence of the string \"deep\"
on an array nested 3 levels deep');",
- "assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deeper').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deeper')[0] === 3, 'message: myNestedArray
should contain exactly one occurence of the string \"deeper\"
on an array nested 4 levels deep');",
- "assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deepest').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deepest')[0] === 4, 'message: myNestedArray
should contain exactly one occurence of the string \"deepest\"
on an array nested 5 levels deep');"
+ "assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deep').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deep')[0] === 2, 'message: myNestedArray
should contain exactly one occurrence of the string \"deep\"
on an array nested 3 levels deep');",
+ "assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deeper').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deeper')[0] === 3, 'message: myNestedArray
should contain exactly one occurrence of the string \"deeper\"
on an array nested 4 levels deep');",
+ "assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deepest').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deepest')[0] === 4, 'message: myNestedArray
should contain exactly one occurrence of the string \"deepest\"
on an array nested 5 levels deep');"
],
"type": "waypoint",
"solutions": [],
"challengeType": 1,
"translations": {}
},
+ {
+ "id": "587d7dac367417b2b25184d3",
+ "title": "Introduction to Objects",
+ "description": [
+ [
+ "",
+ "",
+ "The next data structure we will discuss is the JavaScript object. Like arrays, objects are a fundamental part of JavaScript. However, it is probably safe to say that objects surpass arrays in flexibility, usefulness and in their overall importance to the language — in fact, you may have heard this line before: 'In JavaScript, everything is an object.'{ key1: 'val-1', key2: 'val-2' }
let FCC_User = {", "The above code defines an object called
username: 'awesome_coder',
followers: 572,
points: 1741,
completedProjects: 15
};
FCC_User
that has four properties, each of which map to a specific value. If we wanted to know the number of followers
FCC_User
has, we can access that property by writing:",
"let userData = FCC_User.followers;", "This is called dot notation. Alternatively, we can also access the property with brackets, like so:", "
// userData equals 572
let userData = FCC_User['followers']", "Notice that with bracket notation, we enclosed
// userData equals 572
followers
in quotes. This is because the brackets actually allow us to pass a variable in to be evaluated as a property name (hint: keep this in mind for later!). Had we passed followers
in without the quotes, the JavaScript engine would have attempted to evaluate it as a variable, and a ReferenceError: followers is not defined
would have been thrown.",
- "NOTE:foods
object with three entries. Add three more entries: bananas
with a value of 13
, grapes
with a value of 35
, and strawberries
with a value of 27
."
],
@@ -438,14 +525,14 @@
"id": "587d7b7c367417b2b2512b19",
"title": "Modify an Object Nested Within an Object",
"description": [
- "Objects, and other similar key-value pair data structures, offer some very useful benefits. One clear benefit is that they allow us to structure our data in an intuitive way. They are also very flexible. For instance, you can have properties nested to an arbitrary depth. Values can also be anything, for example a key can store an array, or even another object. Objects are also the foundation for JavaScript Object Notation, or JSON, which is a widely used method of sending data across the web.",
- "Another powerful advantage of key-value pair data structures is constant lookup time. What we mean by this is when you request the value of a specific property you will get the value back in the same amount of time (theoretically) regardless of the number of entries in the object. If you had an object with 5 entries or one that held a collection of 1,000,000 entries you could still retrieve property values or check if a key exists in the same amount of time.",
- "The reason for this fast lookup time is that internally, the object is storing properties using some type of hashing mechanism which allows it to know exactly where it has stored different property values. If you want to learn more about this please take a look at the optional Advanced Data Structures challenges. All you should remember for now is that performant access to flexibly structured data make key-value stores very attractive data structures useful in a wide variety of settings.",
+ "Now let's take a look at a slightly more complex object. Object properties can be nested to an arbitrary depth, and their values can be any type of data supported by JavaScript, including arrays and even other objects. Consider the following:",
+ "let nestedObject = {", + "
id: 28802695164,
date: 'December 31, 2016',
data: {
totalUsers: 99,
online: 80,
onlineStatus: {
active: 67,
away: 13
}
}
};
nestedObject
has three unique keys: id
, whose value is a number, date
whose value is a string, and data
, whose value is an object which has yet another object nested within it. While structures can quickly become complex, we can still use the same notations to access the information we need.",
"nestedObject
, which includes another object nested within it. You can modify properties on this nested object in the same way you modified properties in the last challenge. Set the value of the online
key to 45
."
+ "Here we've defined an object, userActivity
, which includes another object nested within it. You can modify properties on this nested object in the same way you modified properties in the last challenge. Set the value of the online
key to 45
."
],
"challengeSeed": [
- "let nestedObject = {",
+ "let userActivity = {",
" id: 23894201352,",
" date: 'January 1, 2017',",
" data: {",
@@ -458,12 +545,12 @@
"",
"// change code above this line",
"",
- "console.log(nestedObject);"
+ "console.log(userActivity);"
],
"tests": [
- "assert('id' in nestedObject && 'date' in nestedObject && 'data' in nestedObject, 'message: nestedObject
has id
, date
and data
properties');",
- "assert('totalUsers' in nestedObject.data && 'online' in nestedObject.data, 'message: nestedObject
has a data
key set to an object with keys totalUsers
and online
');",
- "assert(nestedObject.data.online === 45, 'message: The online
property nested in the data
key of nestedObject
should be set to 45
');",
+ "assert('id' in userActivity && 'date' in userActivity && 'data' in userActivity, 'message: userActivity
has id
, date
and data
properties');",
+ "assert('totalUsers' in userActivity.data && 'online' in userActivity.data, 'message: userActivity
has a data
key set to an object with keys totalUsers
and online
');",
+ "assert(userActivity.data.online === 45, 'message: The online
property nested in the data
key of userActivity
should be set to 45
');",
"assert.strictEqual(code.search(/online: 45/), -1, 'message: The online
property is set using dot or bracket notation');"
],
"type": "waypoint",
@@ -497,7 +584,7 @@
"",
"}",
"",
- "// change code below this line to test differnt cases:",
+ "// change code below this line to test different cases:",
"console.log(checkInventory(\"apples\"));"
],
"tests": [