Skip to content

Commit 05e7b94

Browse files
authored
Improve Concept Exercise: Elyses Analytic Enchantments (array-analysis) (#1489)
1 parent b7da090 commit 05e7b94

File tree

7 files changed

+213
-95
lines changed

7 files changed

+213
-95
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"blurb": "JavaScript provides a number of useful array methods for analysis.",
3-
"authors": ["peterchu999", "SleeplessByte"],
3+
"authors": ["peterchu999", "SleeplessByte", "pertrai1"],
44
"contributors": []
55
}

concepts/array-analysis/about.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# About
22

3-
In JavaScript, instances of an `Array` are regular objects, decorated with lots of [useful methods][array-docs] from the `Array.prototype`. It includes the `length` property, as well as methods for traversing, analyzing and mutating the array. The array's elements are indexed properties of that array.
3+
In JavaScript, instances of an [`Array`][arrays-concept] are regular objects, decorated with lots of [useful methods][array-docs].
4+
It includes the `length` property, as well as methods for traversing, analyzing and mutating the array.
5+
The array's elements are indexed properties of that array.
46
Instead of manually iterating over those indexed properties, use array analysis.
7+
Many of the built-in functions that analyse the contents of an array, take a function that returns true or false as an argument. Such a function is called [`predicate`][predicate_in_programming]
58

69
In general, using the abstractions/built-in methods is more idiomatic, readable and maintainable than using a `for` or `.forEach` equivalent.
710

@@ -68,4 +71,6 @@ const hasValue42 = values.includes(42);
6871
// => false
6972
```
7073

74+
[predicate_in_programming]: https://derk-jan.com/2020/05/predicate/
7175
[array-docs]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Instance_methods
76+
[arrays-concept]: /tracks/javascript/concepts/arrays

concepts/array-analysis/introduction.md

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Introduction
22

3-
In JavaScript, an array is a list-like structure with no fixed length which can hold any type of primitives or objects, or even mixed types. The array elements can be accessed by their index. Arrays are also given a bunch of built-in methods. Some of these built-in methods can analyse the contents of the array. Many of the built-in functions that analyse the contents of an array, take a [`predicate`][predicate_in_programming] as argument.
3+
[Arrays][arrays-concept] have built-in methods to analyse the contents of the array.
4+
Most of these methods take a function that returns true or false as an argument.
5+
Such a function is called [`predicate`][predicate_in_programming].
46

5-
The built-in functions are meant to be used _instead of a `for` loop_ or the built-in `Array#forEach()`:
7+
The built-in methods are meant to be used _instead of a `for` loop_ or the built-in `forEach` method:
68

79
Example of analysis using a for loop :
810

@@ -24,4 +26,68 @@ numbers.indexOf('two');
2426
// => 1
2527
```
2628

29+
Some other helpful built-in methods that are available to analyze an array are shown below. See [MDN][mdn-array-methods] for a full list of array methods.
30+
31+
## `includes`
32+
33+
> The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate. [^1]
34+
35+
```javascript
36+
const numbers = [1, 'two', 3, 'four'];
37+
numbers.includes(1);
38+
// => true
39+
numbers.includes('one');
40+
// => false
41+
```
42+
43+
## `every`
44+
45+
> The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value. [^2]
46+
47+
```javascript
48+
const numbers = [1, 3, 5, 7, 9];
49+
numbers.every((num) => num % 2 !== 0);
50+
// => true
51+
```
52+
53+
## `some`
54+
55+
> The some() method tests whether at least one element in the array passes the test implemented by the provided function. [^3]
56+
57+
```javascript
58+
const numbers = [1, 3, 5, 7, 9];
59+
numbers.some((num) => num % 2 !== 0);
60+
// => true
61+
```
62+
63+
## `find`
64+
65+
> The find() method returns the value of the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned. [^4]
66+
67+
```javascript
68+
const numbers = [1, 3, 5, 7, 9];
69+
numbers.find((num) => num < 5);
70+
// => 1
71+
```
72+
73+
## `findIndex`
74+
75+
> The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise, it returns -1, indicating that no element passed the test. [^5]
76+
77+
```javascript
78+
const numbers = [1, 3, 5, 7, 9];
79+
numbers.findIndex((num) => num > 7);
80+
// => 4
81+
numbers.findIndex((num) => num > 9);
82+
// => -1
83+
```
84+
85+
[^1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
86+
[^2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every
87+
[^3]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
88+
[^4]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
89+
[^5]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
90+
2791
[predicate_in_programming]: https://derk-jan.com/2020/05/predicate/
92+
[mdn-array-methods]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#instance_methods
93+
[arrays-concept]: /tracks/javascript/concepts/arrays

exercises/concept/elyses-analytic-enchantments/.docs/introduction.md

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Introduction
22

3-
In JavaScript, an array is a list-like structure with no fixed length which can hold any type of primitives or objects, or even mixed types. The array elements can be accessed by their index. Arrays are also given a bunch of built-in methods. Some of these built-in methods can analyse the contents of the array. Many of the built-in functions that analyse the contents of an array, take a [`predicate`][predicate_in_programming] as argument.
3+
[Arrays][arrays-concept] have built-in methods to analyse the contents of the array.
4+
Most of these methods take a function that returns true or false as an argument.
5+
Such a function is called [`predicate`][predicate_in_programming].
46

5-
The built-in functions are meant to be used _instead of a `for` loop_ or the built-in `Array#forEach()`:
7+
The built-in methods are meant to be used _instead of a `for` loop_ or the built-in `forEach` method:
68

79
Example of analysis using a for loop :
810

@@ -24,4 +26,68 @@ numbers.indexOf('two');
2426
// => 1
2527
```
2628

29+
Some other helpful built-in methods that are available to analyze an array are shown below. See [MDN][mdn-array-methods] for a full list of array methods.
30+
31+
## `includes`
32+
33+
> The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate. [^1]
34+
35+
```javascript
36+
const numbers = [1, 'two', 3, 'four'];
37+
numbers.includes(1);
38+
// => true
39+
numbers.includes('one');
40+
// => false
41+
```
42+
43+
## `every`
44+
45+
> The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value. [^2]
46+
47+
```javascript
48+
const numbers = [1, 3, 5, 7, 9];
49+
numbers.every((num) => num % 2 !== 0);
50+
// => true
51+
```
52+
53+
## `some`
54+
55+
> The some() method tests whether at least one element in the array passes the test implemented by the provided function. [^3]
56+
57+
```javascript
58+
const numbers = [1, 3, 5, 7, 9];
59+
numbers.some((num) => num % 2 !== 0);
60+
// => true
61+
```
62+
63+
## `find`
64+
65+
> The find() method returns the value of the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned. [^4]
66+
67+
```javascript
68+
const numbers = [1, 3, 5, 7, 9];
69+
numbers.find((num) => num < 5);
70+
// => 1
71+
```
72+
73+
## `findIndex`
74+
75+
> The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise, it returns -1, indicating that no element passed the test. [^5]
76+
77+
```javascript
78+
const numbers = [1, 3, 5, 7, 9];
79+
numbers.findIndex((num) => num > 7);
80+
// => 4
81+
numbers.findIndex((num) => num > 9);
82+
// => -1
83+
```
84+
85+
[^1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
86+
[^2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every
87+
[^3]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
88+
[^4]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
89+
[^5]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
90+
2791
[predicate_in_programming]: https://derk-jan.com/2020/05/predicate/
92+
[mdn-array-methods]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#instance_methods
93+
[arrays-concept]: /tracks/javascript/concepts/arrays

exercises/concept/elyses-analytic-enchantments/.meta/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"blurb": "Elyse's magic training continues, teaching you about useful built-in methods to analyse arrays.",
33
"authors": ["peterchu999", "SleeplessByte"],
4-
"contributors": [],
4+
"contributors": ["pertrai1"],
55
"files": {
66
"solution": ["enchantments.js"],
77
"test": ["enchantments.spec.js"],
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Design
2+
3+
## Learning objectives
4+
5+
Using an array method to ...
6+
7+
- determine the index of an item in the array
8+
- determine if an item is included in the array
9+
- determine if every item in the array meets a certain criteria
10+
- determine if some items in the array meets a certain criteria
11+
- find the first item that meets a certain criteria
12+
- find the index of an item that meets a certain criteria
13+
14+
## Out of scope
15+
16+
The following topics are out of scope because they are covered in other concepts.
17+
18+
- array transformation (map, filter, etc.)
19+
- array loops (forEach, for...of)
20+
- array manipulation (push, pop, etc.)
21+
22+
## Concepts
23+
24+
- `array-analysis`
25+
26+
## Prerequisites
27+
28+
- `arrays` are needed to understand the basics of arrays

exercises/concept/elyses-analytic-enchantments/enchantments.spec.js

Lines changed: 41 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -9,103 +9,56 @@ import {
99
getFirstEvenCardPosition,
1010
} from './enchantments';
1111

12-
/**
13-
* @template T the expected return type
14-
* @typedef {Array<[number[], number, T]>} TestSingleMatrix
15-
*/
16-
17-
/**
18-
* @template T the expected return type
19-
* @typedef {Array<[number[], T]>} TestAllMatrix
20-
**/
21-
22-
describe('elyses analytic enchantments', () => {
23-
describe('getCardPosition', () => {
24-
/** @type {TestSingleMatrix<number>} */
25-
const getCardPositionTestCases = [
26-
[[1, 2, 3], 1, 0],
27-
[[1, 2, 2], 2, 1],
28-
[[1, 2, 3], 4, -1],
29-
];
30-
31-
getCardPositionTestCases.forEach(([array, item, expected]) => {
32-
test(`getCardIndex([${array}], ${item})`, () => {
33-
expect(getCardPosition(array, item)).toStrictEqual(expected);
34-
});
35-
});
12+
describe('getCardPosition', () => {
13+
test('when it is the first card', () => {
14+
expect(getCardPosition([1, 2, 3], 1)).toBe(0);
3615
});
37-
38-
describe('doesStackIncludeCard', () => {
39-
/** @type {TestSingleMatrix<boolean>} */
40-
const doesStackIncludeCardTestCases = [
41-
[[1, 2, 3], 1, true],
42-
[[1, 2, 3], 4, false],
43-
];
44-
45-
doesStackIncludeCardTestCases.forEach(([array, item, expected]) => {
46-
test(`doesStackIncludeCard([${array}],${item})`, () => {
47-
expect(doesStackIncludeCard(array, item)).toBe(expected);
48-
});
49-
});
16+
test('when the card is not found', () => {
17+
expect(getCardPosition([1, 2, 3], 4)).toBe(-1);
5018
});
19+
});
5120

52-
describe('isEachCardEven', () => {
53-
/** @type {TestAllMatrix<boolean>} */
54-
const isEachCardEvenTestCases = [
55-
[[1], false],
56-
[[2, 5], false],
57-
[[2, 4, 8, 6], true],
58-
];
59-
60-
isEachCardEvenTestCases.forEach(([array, expected]) => {
61-
test(`isEachCardEven([${array}])`, () => {
62-
expect(isEachCardEven(array)).toStrictEqual(expected);
63-
});
64-
});
21+
describe('doesStackIncludeCard', () => {
22+
test('when there is a card found', () => {
23+
expect(doesStackIncludeCard([1, 2, 3], 1)).toBe(true);
6524
});
66-
67-
describe('doesStackIncludeOddCard', () => {
68-
/** @type {TestAllMatrix<boolean>} */
69-
const doesStackIncludesOddCardTestCases = [
70-
[[2, 4, 6], false],
71-
[[2, 5], true],
72-
[[1, 3, 5, 7], true],
73-
];
74-
75-
doesStackIncludesOddCardTestCases.forEach(([array, expected]) => {
76-
test(`doesStackIncludeOddCard([${array}])`, () => {
77-
expect(doesStackIncludeOddCard(array)).toStrictEqual(expected);
78-
});
79-
});
25+
test('when a card is not found', () => {
26+
expect(doesStackIncludeCard([1, 2, 3], 4)).toBe(false);
8027
});
28+
});
8129

82-
describe('getFirstOddCard', () => {
83-
/** @type {TestAllMatrix<number | undefined>} */
84-
const getFirstOddCardTestCases = [
85-
[[2, 4, 1, 3], 1],
86-
[[1, 2], 1],
87-
[[4, 2, 6], undefined],
88-
];
30+
describe('isEachCardEven', () => {
31+
test('when all cards are even', () => {
32+
expect(isEachCardEven([2, 4, 6])).toBe(true);
33+
});
34+
test('when any card is odd', () => {
35+
expect(isEachCardEven([2, 5, 6])).toBe(false);
36+
});
37+
});
8938

90-
getFirstOddCardTestCases.forEach(([array, expected]) => {
91-
test(`getFirstOddCard([${array}])`, () => {
92-
expect(getFirstOddCard(array)).toStrictEqual(expected);
93-
});
94-
});
39+
describe('doesStackIncludeOddCard', () => {
40+
test('should be true if odd number card is found', () => {
41+
expect(doesStackIncludeOddCard([2, 5])).toBe(true);
9542
});
43+
test('should be false if no odd number card is found', () => {
44+
expect(doesStackIncludeOddCard([2, 4, 6])).toBe(false);
45+
});
46+
});
9647

97-
describe('getFirstEvenCardPosition', () => {
98-
/** @type {TestAllMatrix<number>} */
99-
const getFirstEvenCardPositionTestCases = [
100-
[[2, 4, 1, 3], 0],
101-
[[1, 2], 1],
102-
[[1, 3, 5], -1],
103-
];
48+
describe('getFirstOddCard', () => {
49+
test('should return the first odd card found', () => {
50+
expect(getFirstOddCard([2, 4, 1, 3])).toBe(1);
51+
});
52+
test('should return undefined if odd card is not found', () => {
53+
expect(getFirstOddCard([4, 2, 6])).toBeUndefined();
54+
});
55+
});
10456

105-
getFirstEvenCardPositionTestCases.forEach(([array, expected]) => {
106-
test(`getFirstEvenCardPosition([${array}])`, () => {
107-
expect(getFirstEvenCardPosition(array)).toStrictEqual(expected);
108-
});
109-
});
57+
describe('getFirstEvenCardPosition', () => {
58+
test('should return position of first even card', () => {
59+
expect(getFirstEvenCardPosition([2, 4, 1, 3])).toBe(0);
60+
});
61+
test('should return -1 when the card is not found', () => {
62+
expect(getFirstEvenCardPosition([1, 3, 5])).toBe(-1);
11063
});
11164
});

0 commit comments

Comments
 (0)