Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Concept Exercise: For Loops #1059

Merged
merged 22 commits into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions concepts/for-loops/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# About

## General Syntax

The for loop is one of the most commonly used statements to repeatedly execute some logic.
In JavaScript it consists of the `for` keyword, a _header_ wrapped in round brackets and a code block that contains the _body_ of the loop wrapped in curly brackets.

```javascript
for (initialization; condition; step) {
// code that is executed repeatedly as long as the condition is true
}
```

## Header

The initialization usually sets up a counter variable, the condition checks whether the loop should be continued or stopped and the step increments the counter at the end of each repetition.
The individual parts of the header are separated by semicolons.

```javascript
const list = ['a', 'b', 'c'];
for (let i = 0; i < list.length; i++) {
// code that should be executed for each item in the array
}
```

All three parts of the header are optional.
This is rarely utilized in practice.
You can read more about this in the [MDN documentation][mdn-optional-header-parts].

## Nested For Loops

For loops can be nested, for example to iterate over nested (multi-dimensional) [arrays][concept-arrays].
Make sure to set up a different counter variable for each loop.

```javascript
const coords = [
[1, 2],
[4, 7],
[10, -3],
];

for (let i = 0; i < coords.length; i++) {
for (let j = 0; j < coords[i].length; j++) {
// do something with coords[i][j]
}
}
```

## Break, Continue and Labels

Inside a loop body you can use the `break` keyword to stop the execution of the loop entirely.
In contrast, the keyword `continue` only stops the execution of the current iteration and continues with the next one.

When working with nested loops, `break` and `continue` always apply to the innermost loop by default.
You can use labels to change that behavior.
A label is an identifier name followed by a colon.
It is placed in front (or above) the loop.
Such a label can then be combined with `break` or `continue` to define to which loop the statement should apply to.

```javascript
outer: for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
// ...
if (j > 5) {
continue outer;
}
// ...
}
}
```

## Loop Counter and Asynchronous Code

You need to be careful to correctly declare your counter variable when dealing with [asynchronous code][mdn-concept-asynchronous].
Let us look at an example where we sum up the counter variable asynchronously with `setTimeout` after waiting for 1s.
When declaring the counter with `var` or with `let` but outside the header, the code does not yield the expected result.

<!-- prettier-ignore-start -->
```javascript
let sum = 0;
for (var i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 12 instead of 6 (1+2+3)
```
<!-- prettier-ignore-end -->

<!-- prettier-ignore-start -->
```javascript
let sum = 0;
let i;
for (i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// same here, eventually sum will be 12 instead of 6 (1+2+3)
```
<!-- prettier-ignore-end -->

In these two cases `i` is not scoped to one specific loop iteration.
By the time the sum is calculated, `i` already reached its final value `4` which leads to the sum being `4 + 4 + 4 = 12`.

This problem can be avoided by declaring the counter with `let` inside the header.
This has the special effect that each iteration gets its very own variable `let i` that is scoped to exactly that one execution of the loop body.
So when the sum is calculated later, each [callback][concept-callbacks] function refers to their own variable `i` that still holds the correct value.

<!-- prettier-ignore-start -->
```javascript
let sum = 0;
for (let i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 6 (1+2+3) as expected
```
<!-- prettier-ignore-end -->

[mdn-optional-header-parts]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for#optional_for_expressions
[concept-arrays]: /tracks/javascript/concepts/arrays
[concept-callbacks]: /tracks/javascript/concepts/callbacks
[mdn-concept-asynchronous]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Concepts
20 changes: 20 additions & 0 deletions concepts/for-loops/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Introduction

The for loop is one of the most commonly used statements to repeatedly execute some logic.
In JavaScript it consists of the `for` keyword, a _header_ wrapped in round brackets and a code block that contains the _body_ of the loop wrapped in curly brackets.

```javascript
for (initialization; condition; step) {
// code that is executed repeatedly as long as the condition is true
}
```

The initialization usually sets up a counter variable, the condition checks whether the loop should be continued or stopped and the step increments the counter at the end of each repetition.
The individual parts of the header are separated by semicolons.

```javascript
const list = ['a', 'b', 'c'];
for (let i = 0; i < list.length; i++) {
// code that should be executed for each item list[i]
}
```
18 changes: 18 additions & 0 deletions concepts/for-loops/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for",
"description": "MDN: For Loop"
},
{
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break",
"description": "MDN: break"
},
{
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue",
"description": "MDN: continue"
},
{
"url": "https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/label",
"description": "MDN: Label"
}
]
35 changes: 35 additions & 0 deletions concepts/increment-decrement/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# About

JavaScript has an increment and a decrement operator.
They modify a variable in place.
`++` adds one to a number, `--` subtracts one from a number.

```javascript
let i = 3;
i++;
// i is now 4

let j = 0;
j--;
// j is now -1
```

The example above shows the postfix increment/decrement operator.
In this case the operator is placed after the variable and the return value of the expression is the value of the variable _before_ the increase/decrease.

```javascript
let a = 3;
let b = a++;
// a = 4
// b = 3
```

There is also the prefix variant where the operator is placed before the variable.
Then the return value is the value of the variable _after_ the increase/decrease.

```javascript
let a = 3;
let b = ++a;
// a = 4
// b = 4
```
15 changes: 15 additions & 0 deletions concepts/increment-decrement/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Introduction

JavaScript has an increment and a decrement operator.
They modify a variable in place.
`++` adds one to a number, `--` subtracts one from a number.

```javascript
let i = 3;
i++;
// i is now 4

let j = 0;
j--;
// j is now -1
```
6 changes: 6 additions & 0 deletions concepts/increment-decrement/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#increment_and_decrement",
"description": "MDN: Increment and Decrement"
}
]
20 changes: 20 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@
"concepts": ["comparison", "conditionals"],
"prerequisites": ["booleans", "numbers", "strings"],
"status": "beta"
},
{
"slug": "bird-watcher",
"name": "Bird Watcher",
"uuid": "3e648aa0-9ce7-4041-93d2-2b95f3832824",
"concepts": ["for-loops", "increment-decrement"],
"prerequisites": ["arrays", "comparison", "conditionals"],
"status": "beta"
}
],
"practice": [
Expand Down Expand Up @@ -1600,6 +1608,18 @@
"slug": "comparison",
"name": "Comparison",
"blurb": "Compare values using operators to check greater than, less than, equals and not equals"
},
{
"uuid": "be301f37-6cf4-4688-949e-75a8976a91e3",
"slug": "for-loops",
"name": "For Loops",
"blurb": "Execute code repeatedly for different values of an iterator"
},
{
"uuid": "a2347a19-1e44-449b-9741-94eda00d8ba7",
"slug": "increment-decrement",
"name": "Increment and Decrement Operators",
"blurb": "Shorthand notation to increment and decrement numbers using special operators"
}
],
"key_features": [
Expand Down
24 changes: 24 additions & 0 deletions exercises/concept/bird-watcher/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Hints

## 1. Determine the total number of birds that you counted so far

- Refer to the exercise introduction for an example how to use a for loop to iterate over an array.
- Use a helper variable to store the total count and increase that variable as you go through the array.
- Think about the correct initial value for that helper variable.
- Refer back to the [array concept][concept-arrays] to recap how to retrieve values from an array.

## 2. Calculate the number of visiting birds in a specific week

- This task is similar to the first one, you can copy your code as a starting point.
- Think about which indexes in the array you would need to take into account for week number 1 and 2, respectively.
- Now find a general way to calculate the first and the last index that should be considered.
- With that you can set up the for loop to only iterate over the relevant section of the array.

## 3. Fix a counting mistake

- Again you need to set up a for loop to iterate over the whole bird count array.
- This time you only need to visit every second entry in the array.
- Change the step so the counter variable is increased accordingly after each iteration.
- In the body of the for loop you can use the increment operator to change the value of an element in an array in place.

[concept-arrays]: /tracks/javascript/concepts/arrays
47 changes: 47 additions & 0 deletions exercises/concept/bird-watcher/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Instructions

You are an avid bird watcher that keeps track of how many birds have visited your garden.
Usually you use a tally in a notebook to count the birds but you want to better work with your data.
You already digitalized the bird counts per day for the past weeks that you kept in the notebook.

Now you want to determine the total number of birds that you counted, calculate the bird count for a specific week and correct a counting mistake.

## 1. Determine the total number of birds that you counted so far

Let us start analyzing the data by getting a high level view. Find out how many birds you counted in total since you started your logs.

Implement a function `totalBirdCount` that accepts an array that contains the bird count per day. It should return the total number of birds that you counted.

```javascript
birdsPerDay = [2, 5, 0, 7, 4, 1, 3, 0, 2, 5, 0, 1, 3, 1];
totalBirdCount(birdsPerDay);
// => 34
```

## 2. Calculate the number of visiting birds in a specific week

Now that you got a general feel for your bird count numbers, you want to make a more fine-grained analysis.

Implement a function `birdsInWeek` that accepts an array of bird counts per day and a week number.
It returns the total number of birds that you counted in that specific week. You can assume weeks are always tracked completely.

```javascript
birdsPerDay = [2, 5, 0, 7, 4, 1, 3, 0, 2, 5, 0, 1, 3, 1];
birdsInWeek(birdsPerDay, 2);
// => 12
```

## 3. Fix a counting mistake

You realized that all the time you were trying to keep track of the birds, there was one bird that was hiding in a far corner of the garden.
You figured out that this bird always spent every second day in your garden.
You do not know exactly where it was in between those days but definitely not in your garden.
Your bird watcher intuition also tells you that the bird was in your garden on the first day that you tracked in your list.

Given this new information, write a function `fixBirdCountLog` that takes an array of birds counted per day as an argument and returns that same array after correcting the counting mistake.

```javascript
birdsPerDay = [2, 5, 0, 7, 4, 1];
fixBirdCountLog(birdsPerDay);
// => [3, 5, 1, 7, 5, 1]
```
34 changes: 34 additions & 0 deletions exercises/concept/bird-watcher/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Introduction

The for loop is one of the most commonly used statements to repeatedly execute some logic.
In JavaScript it consists of the `for` keyword, a _header_ wrapped in round brackets and a code block that contains the _body_ of the loop wrapped in curly brackets.

```javascript
for (initialization; condition; step) {
// code that is executed repeatedly as long as the condition is true
}
```

The initialization usually sets up a counter variable, the condition checks whether the loop should be continued or stopped and the step increments the counter at the end of each repetition.
The individual parts of the header are separated by semicolons.

```javascript
const list = ['a', 'b', 'c'];
for (let i = 0; i < list.length; i++) {
// code that should be executed for each item list[i]
}
```

Defining the step is often done using JavaScripts increment or decrement operator as shown in the example above.
These operators modify a variable in place.
`++` adds one to a number, `--` subtracts one from a number.

```javascript
let i = 3;
i++;
// i is now 4

let j = 0;
j--;
// j is now -1
```
29 changes: 29 additions & 0 deletions exercises/concept/bird-watcher/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"root": true,
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 7,
"sourceType": "module"
},
"globals": {
"BigInt": true
},
"env": {
"es6": true,
"node": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings"
],
"rules": {
"linebreak-style": "off",

"import/extensions": "off",
"import/no-default-export": "off",
"import/no-unresolved": "off",
"import/prefer-default-export": "off"
}
}
3 changes: 3 additions & 0 deletions exercises/concept/bird-watcher/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
yarn-error.log

Loading