Calling all beginners - part II: Return Of The Arrays!
Tags: beginners, javascript, tutorial
Published: 2022-07-13 09:40:51

_Cover photo by [Faris Mohammed](https://unsplash.com/@pkmfaris?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)_
___
  
Hello, coders! :computer:

In this second post aimed at beginners we'll continue manipulating arrays because:
1. arrays are fun
1. you will have to deal with arrays A LOT in your career so you might as well feel comfortable working with them

## Context
You're given a list of purchases customers have made over the past few months. Given the quantity it's fair to say it's not a very popular shop...

```javascript
const purchases = [
    {item: 'socks', amount: 25.98, date: '2022-05-07 09:31:29'},
    {item: 'jacket', amount: 145.98, date: '2022-05-17 17:01:09'},
    {item: 'cap', amount: 12.99, date: '2022-05-17 17:03:12'},
    {item: 'socks', amount: 43.99, date: '2022-06-11 18:24:16'},
    {item: 'cap', amount: 13.99, date: '2022-06-11 18:24:16'},
    {item: 'jacket', amount: 132.99, date: '2022-06-21 11:21:35'},
    {item: 'socks', amount: 13.99, date: '2022-06-23 09:43:28'},
    {item: 'socks', amount: 12.99, date: '2022-07-01 13:14:56'},
    {item: 'jacket', amount: 132.99, date: '2022-07-03 15:24:24'},
    {item: 'cap', amount: 32.99, date: '2022-07-05 11:14:15'},
    {item: 'socks', amount: 13.99, date: '2022-07-07 11:14:15'},
];
```

## Exercise 1
Your task is to compute the total amount of purchases per month and store that in an object named `monthlyRevenue`.

### Expected object
:warning: Amounts have 2 decimal places.
```javascript
let monthlyRevenue = {
  '2022-05': 184.95,
  '2022-06': 204.96,
  '2022-07': 192.96
}
```

## <a name="ex1solution"></a>Solution to exercise 1

:point_down:
{% details Click for a step by step guide %}

Let's see how we can break down what we need to do.
1. loop through `purchases`
1. for each purchase we need to do some sort of date manipulation to get the year/month part
1. then we add the amount to `monthlyRevenue` for the date found in our previous step.
1. then we'll see what's left to do.

Sounds good. Let's code! :keyboard:

```javascript
// purchases omitted for readability
let monthlyRevenue = {}
// first step: loop!
purchases.forEach(function (purchase) {
    // do something
})
```

Easy.
Now, how do we get the year/month part from each `purchase.date`?
Well, `purchase.date` is a string and the 7 first characters are year and month which is what we need.
So how about using [`substring`](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/String/substring)?
```javascript
purchase.date.substring(0, 7)
```

Let's try the following:
```javascript
// purchases omitted for readability
let monthlyRevenue = {}
// first step: loop!
purchases.forEach(function (purchase) {
    // second step: year/month part
    const purchaseDate = purchase.date.substring(0, 7);
    console.log(purchaseDate);
})
```
which outputs:
```
2022-05
2022-05
2022-05
2022-06
2022-06
2022-06
2022-06
2022-07
2022-07
2022-07
2022-07
```
All good!

Onto step 3: sum of amounts.

Now that we have the year/month part we can store amounts in `monthlyRevenue[purchaseDate]`.

Let's see what happens when we innocently add each `purchase.amount` to `monthlyRevenue[purchaseDate]` to get a sum.
```javascript
// purchases omitted for readability
let monthlyRevenue = {}
// first step: loop!
purchases.forEach(function (purchase) {
    // second step: year/month part
    const purchaseDate = purchase.date.substring(0, 7);
    // step 3: sum
    monthlyRevenue[purchaseDate] += purchase.amount;
})
console.log(monthlyRevenue);
```
outputs:
```
Object {
  "2022-05": NaN,
  "2022-06": NaN,
  "2022-07": NaN
}
```
Ouch! `NaN`? :bread:?
It means `Not a Number` and is due to the fact that we're trying to add a number to `monthlyRevenue[purchaseDate]` which is initially `undefined`.
We need to make sure it's `0` before adding anything to it.
```javascript
monthlyRevenue[purchaseDate] = purchase.amount + (monthlyRevenue[purchaseDate] || 0);
```
should do the trick!
`||` return the rightmost element if the first one is `falsy`.
So when we first access `monthlyRevenue[purchaseDate]` it will return `undefined` which is `falsy` so `||` returns `0`.
From now on `monthlyRevenue[purchaseDate]` will no longer be `falsy`.

Let's update our code:
```javascript
// purchases omitted for readability
let monthlyRevenue = {}
// first step: loop!
purchases.forEach(function (purchase) {
    // second step: year/month part
    const purchaseDate = purchase.date.substring(0, 7);
    // step 3: sum
    monthlyRevenue[purchaseDate] = purchase.amount + (monthlyRevenue[purchaseDate] || 0);
})
console.log(monthlyRevenue);
```

and see the output:
```
Object {
  "2022-05": 184.95,
  "2022-06": 204.96000000000004,
  "2022-07": 192.96000000000004
}
```
Hooray! :rocket:

Wait, Why so many decimal places?! It has to do with floating points. It's a topic in its own right and I won't go into details here. What I can tell you though, is that there we're not done yet!

Looking back at the exercise's description I see a :warning: sign to let us know **numbers must have 2 decimal places**.

And that's step 4 which I mentioned earlier. ^^

Let's round things after the loop that populates `monthlyRevenue`. We'll use `toFixed`:
```javascript
// step 4: rounding numbers
for (let yearMonth in monthlyRevenue) {
    monthlyRevenue[yearMonth] = monthlyRevenue[yearMonth].toFixed(2);
}
console.log(monthlyRevenue);
```
which outputs
```
Object {
  "2022-05": "184.95",
  "2022-06": "204.96",
  "2022-07": "192.96"
}
```

Almost there! `toFixed` returns a string and we want a number so we call `Number` to parse strings and voilà:
```javascript
// step 4: rounding numbers
for (let yearMonth in monthlyRevenue) {
    monthlyRevenue[yearMonth] = Number(monthlyRevenue[yearMonth].toFixed(2));
}
console.log(monthlyRevenue);
```

What does the output look like?
```
Object {
  "2022-05": 184.95,
  "2022-06": 204.96,
  "2022-07": 192.96
}
```
:rocket: Now we're talking. It outputs exactly what was asked.

## Putting it all together
Here's all the code:
```javascript
const purchases = [
    {item: 'socks', amount: 25.98, date: '2022-05-07 09:31:29'},
    {item: 'jacket', amount: 145.98, date: '2022-05-17 17:01:09'},
    {item: 'cap', amount: 12.99, date: '2022-05-17 17:03:12'},
    {item: 'socks', amount: 43.99, date: '2022-06-11 18:24:16'},
    {item: 'cap', amount: 13.99, date: '2022-06-11 18:24:16'},
    {item: 'jacket', amount: 132.99, date: '2022-06-21 11:21:35'},
    {item: 'socks', amount: 13.99, date: '2022-06-23 09:43:28'},
    {item: 'socks', amount: 12.99, date: '2022-07-01 13:14:56'},
    {item: 'jacket', amount: 132.99, date: '2022-07-03 15:24:24'},
    {item: 'cap', amount: 32.99, date: '2022-07-05 11:14:15'},
    {item: 'socks', amount: 13.99, date: '2022-07-07 11:14:15'},
];

let monthlyRevenue = {}
// first step: loop!
purchases.forEach(function (purchase) {
    // second step: year/month part
    const purchaseDate = purchase.date.substring(0, 7);
    // step 3: sum
    monthlyRevenue[purchaseDate] = purchase.amount + (monthlyRevenue[purchaseDate] || 0);
})
// step 4: rounding numbers
for (let yearMonth in monthlyRevenue) {
    monthlyRevenue[yearMonth] = Number(monthlyRevenue[yearMonth].toFixed(2));
}
console.log(monthlyRevenue);
```

:sweat_smile: That was a long ass guide!

Too long? Too detailed? Let me know in the comments! :speech_balloon:

{% enddetails %}

## Homework :house_with_garden:
Now that arrays and objects have no secrets for you, here's your assignment.
>Create a list of best and worst selling items of each month.
>Best and worst are defined by the revenue they generated.

Expected result:
```javascript
let topFlops = {
  "2022-05": {
    top: 'jacket',
    flop: 'cap'
  },
  "2022-06": {
    top: 'jacket',
    flop: 'cap'
  },
  "2022-07": {
    top: 'jacket',
    flop: 'socks'
  }
}
```

Happy coding! :computer: