Calling all beginners: solution to part II's homework
Tags: javascript, beginners, tutorial, webdev
Published: 2022-07-20 07:38:53

Hello, coders! :computer:

In the [previous episode](https://dev.to/joolsmcfly/calling-all-beginners-part-ii-return-of-the-arrays-1obd) of this beginners series I gave you an exercise based on the following initial data:
```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'},
];
```

>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
const topFlops = {
  "2022-05": {
    top: 'jacket',
    flop: 'cap'
  },
  "2022-06": {
    top: 'jacket',
    flop: 'cap'
  },
  "2022-07": {
    top: 'jacket',
    flop: 'socks'
  }
}
```

Let's see how we could go about implementing a solution.

## Step by step solution
First, let's write in plain English what we need to do:
1. group purchases by month and items
1. get first and last item of each month and make them `top` and `flop`

Sounds good. Let's write our code outline.

```javascript
const purchases = [ /* omitted for readability */];
const itemsMonthlyRevenue = getItemsMonthlyRevenue(purchases);
const topFlop = getTopFlopFromMonthlyRevenue(itemsMonthlyRevenue);
```
---
### `getItemsMonthlyRevenue`
`getItemsMonthlyRevenue` needs to add one level compared to what we had in [Part II's first exercise](https://dev.to/joolsmcfly/calling-all-beginners-part-ii-return-of-the-arrays-1obd#ex1solution) to store items' monthly revenue.

```javascript
const getItemsMonthlyRevenue = (purchases) => {
    let monthlyRevenue = {}
    purchases.forEach(function (purchase) {
        const purchaseDate = purchase.date.substring(0, 7);
        if (monthlyRevenue[purchaseDate] === undefined) {
            monthlyRevenue[purchaseDate] = {}
        }
        monthlyRevenue[purchaseDate][purchase.item] = purchase.amount + (monthlyRevenue[purchaseDate][purchase.item] || 0);
    })

    return monthlyRevenue;
}

const purchases = [ /* omitted for readability */];
const itemsMonthlyRevenue = getItemsMonthlyRevenue(purchases);
console.log(JSON.stringify(itemsMonthlyRevenue, null, 2));
```

The main difference with Part II's first exercise is that `monthlyRevenue[purchaseDate]` is now an object so we need to make sure it's initialized before accessing it.

Let's run it and see what we get in the console.

Output:
```
{
  "2022-05": {
    "socks": 25.98,
    "jacket": 145.98,
    "cap": 12.99
  },
  "2022-06": {
    "socks": 57.980000000000004,
    "cap": 13.99,
    "jacket": 132.99
  },
  "2022-07": {
    "socks": 26.98,
    "jacket": 132.99,
    "cap": 32.99
  }
}
```

Excellent. Onto `getTopFlopFromMonthlyRevenue`!

---

### `getTopFlopFromMonthlyRevenue`

```javascript
const getTopFlopFromMonthlyRevenue = (monthlyRevenue) => {
    let topFlop = {};
    const NAME_IDX = 0;
    const REVENUE_IDX = 1;
    for (let month in monthlyRevenue) {
        // step 1: get an array of item/monthlyRevenue
        const productsSales = Object.entries(monthlyRevenue[month]);

        // step 2: sort by revenue
        productsSales.sort(function (p1, p2) {
            return p2[REVENUE_IDX] < p1[REVENUE_IDX] ? 1 : -1;
        })

        // step 3: fill the topFlop array object
        topFlop[month] = ({
            flop: productsSales[0][NAME_IDX],
            top: productsSales[productsSales.length - 1][NAME_IDX]
        })
    }

    return topFlop;
}

```

What's going on here?
Each month holds a list of items as keys and revenue as values and that's what we want to sort.
I make use of [`Object.entries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) which returns an array of `[key, value]` tuples. Example:
```javascript
console.log(monthlyRevenue['2022-06']);
// outputs
[
​  [ "socks", 57.980000000000004 ],
​  [ "cap", 13.99 ],​
  [ "jacket", 132.99 ],
]
```

We can now sort that array and get the first and last element which will be out `flop` and `top` respectively.

### Putting it all together

```javascript
const getItemsMonthlyRevenue = (purchases) => {
    let monthlyRevenue = {}
    purchases.forEach(function (purchase) {
        const purchaseDate = purchase.date.substring(0, 7);
        if (monthlyRevenue[purchaseDate] === undefined) {
            monthlyRevenue[purchaseDate] = {}
        }
        monthlyRevenue[purchaseDate][purchase.item] = purchase.amount + (monthlyRevenue[purchaseDate][purchase.item] || 0);
    })

    return monthlyRevenue;
}

const getTopFlopFromMonthlyRevenue = (monthlyRevenue) => {
    let topFlop = {};
    const NAME_IDX = 0;
    const REVENUE_IDX = 1;
    for (let month in monthlyRevenue) {
        const productsSales = Object.entries(monthlyRevenue[month]);

        productsSales.sort(function (p1, p2) {
            return p2[REVENUE_IDX] < p1[REVENUE_IDX] ? 1 : -1;
        })

        topFlop[month] = ({
            flop: productsSales[0][NAME_IDX],
            top: productsSales[productsSales.length - 1][NAME_IDX]
        })
    }

    return topFlop;
}


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'},
];
const itemsMonthlyRevenue = getItemsMonthlyRevenue(purchases);
const topFlop = getTopFlopFromMonthlyRevenue(itemsMonthlyRevenue);
console.log(JSON.stringify(topFlop, null, 2));
```

Hope it helps you, as a beginner, to see how to tackle a task.

Happy coding! :keyboard: