Ctsa3
Ctsa3

Reputation: 143

Can I double reduce?

PROBLEM: I have a dataset in CSV format that has some key metrics I need to manipulate. I have regions, dates and sales volumes. I want to combine the similar regions together. I also want to combine the similar dates and add the sales volume per region per combined date.

SOLUTION:

const tableNoHeader = table
         .split('\n')
         .map(line => line.split(','))
         .slice(1)
         .reduce((region, row) => {
            region[row[10]] = region[row[10]] || [];
            region[row[10]].push({
              weekOf: row[5],
              sales : parseFloat(row[8]) >= 0 
                         && parseFloat(row[9]) >= 0 
                            ? parseFloat(row[8]) + parseFloat(row[9]) 
                            : ""
              });
              return region;
           }, {});

I’ve successfully used reduce to combine all the duplicate regions together but now within each region I have duplicate dates and I want to have those reduced(?) as well.

Not sure if that’s possible or how to do this effectively...

Here is some sample data from the CSV:

First Name, Last Name, Full Name, Key, Role, Date, Unit Type 1, Unit Type 2, Units Sales 1, Units Sales 2, Region, Position, Hire
John, Doe, John Doe, JohnDoe, Sales, 22-Feb-21, Commercial, Commercial, 12, 2, West, Associate, 2017
Jane, Doe, Jane Doe, JaneDoe, Sales, 22-Feb-21, Commercial, Commercial, 7, 22, Central, Associate, 2019
Jane, Doe, Jane Doe, JaneDoe, Sales, 01-Mar-21, Commercial, Commercial, 21, 1, Central, Associate, 2019
John, Doe, John Doe, JohnDoe, Sales, 01-Mar-21, Commercial, Commercial, 4, 8, Central, Associate, 2012
Jake, Doe, Jake Doe, JakeDoe, Sales, 22-Feb-21, Commercial, Commercial, 2, 2, West, Associate, 2019

Any feedback is appreciated!

Upvotes: 0

Views: 247

Answers (3)

Mister Jojo
Mister Jojo

Reputation: 22265

So, as Kaiido reminded me of the idea of placing a second reduce after the first, here is a second double proposition:

the first One idea is about changing the result structure (anything is objects) and ther is no needs of a second reduce

//                0           1          2          3    4     5     6            7            8              9              10      11        12
const csvData = `First Name, Last Name, Full Name, Key, Role, Date, Unit Type 1, Unit Type 2, Units Sales 1, Units Sales 2, Region, Position, Hire
John, Doe, John Doe, JohnDoe, Sales, 22-Feb-21, Commercial, Commercial, 12, 2, West, Associate, 2017
Jane, Doe, Jane Doe, JaneDoe, Sales, 22-Feb-21, Commercial, Commercial, 7, 22, Central, Associate, 2019
Jane, Doe, Jane Doe, JaneDoe, Sales, 01-Mar-21, Commercial, Commercial, 21, 1, Central, Associate, 2019
John, Doe, John Doe, JohnDoe, Sales, 01-Mar-21, Commercial, Commercial, 4, 8, Central, Associate, 2012
Jake, Doe, Jake Doe, JakeDoe, Sales, 22-Feb-21, Commercial, Commercial, 2, 2, West, Associate, 2019'`

const tableNoHeader = csvData
  .split('\n').slice(1) 
  .map(line =>
    {  //  0          1         2         3    4     5       6          7          8            9            10      11        12
    let [ FirstName, LastName, FullName, Key, Role, weekOf, UnitType1, UnitType2, UnitsSales1, UnitsSales2, region, Position, Hire]
        = line.split(/, |,/)
    return ({ region, weekOf, sales : (+UnitsSales1) + (+UnitsSales2) })
    })     
  .reduce((res,{region,weekOf,sales}) =>
    {
    res[region] = res[region] || {}
    res[region][weekOf] = res[region][weekOf] || 0
    res[region][weekOf] += sales
    return res
    }, {})
console.log(  tableNoHeader )
.as-console-wrapper { max-height: 100% !important; top: 0; }

this second solution is the same, but with a second retuce to transform the previous result to the same structure of my first post, but have nothing to do with an idea of grouping values.

//                0           1          2          3    4     5     6            7            8              9              10      11        12
const csvData = `First Name, Last Name, Full Name, Key, Role, Date, Unit Type 1, Unit Type 2, Units Sales 1, Units Sales 2, Region, Position, Hire
John, Doe, John Doe, JohnDoe, Sales, 22-Feb-21, Commercial, Commercial, 12, 2, West, Associate, 2017
Jane, Doe, Jane Doe, JaneDoe, Sales, 22-Feb-21, Commercial, Commercial, 7, 22, Central, Associate, 2019
Jane, Doe, Jane Doe, JaneDoe, Sales, 01-Mar-21, Commercial, Commercial, 21, 1, Central, Associate, 2019
John, Doe, John Doe, JohnDoe, Sales, 01-Mar-21, Commercial, Commercial, 4, 8, Central, Associate, 2012
Jake, Doe, Jake Doe, JakeDoe, Sales, 22-Feb-21, Commercial, Commercial, 2, 2, West, Associate, 2019'`

const tableNoHeader = csvData
  .split('\n').slice(1) 
  .map(line =>
    {  //  0          1         2         3    4     5       6          7          8            9            10      11        12
    let [ FirstName, LastName, FullName, Key, Role, weekOf, UnitType1, UnitType2, UnitsSales1, UnitsSales2, region, Position, Hire]
        = line.split(/, |,/)
    return ({ region, weekOf, sales : (+UnitsSales1) + (+UnitsSales2) })
    })     
  .reduce((res,{region,weekOf,sales},i,{[i+1]:nxt}) =>
    {
    res[region] = res[region] || {}
    res[region][weekOf] = res[region][weekOf] || 0
    res[region][weekOf] += sales
    if (nxt) return res
    else return Object.keys(res).reduce((x,rg)=>
      {
      x[rg] = Object.entries(res[rg]).map(([k,v])=>({weekOf:k,sales:v}))
      return x
      } ,{})
    }, {})

console.log( tableNoHeader )
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Mister Jojo
Mister Jojo

Reputation: 22265

I think this is it ?

//                0           1          2          3    4     5     6            7            8              9              10      11        12
const csvData = `First Name, Last Name, Full Name, Key, Role, Date, Unit Type 1, Unit Type 2, Units Sales 1, Units Sales 2, Region, Position, Hire
John, Doe, John Doe, JohnDoe, Sales, 22-Feb-21, Commercial, Commercial, 12, 2, West, Associate, 2017
Jane, Doe, Jane Doe, JaneDoe, Sales, 22-Feb-21, Commercial, Commercial, 7, 22, Central, Associate, 2019
Jane, Doe, Jane Doe, JaneDoe, Sales, 01-Mar-21, Commercial, Commercial, 21, 1, Central, Associate, 2019
John, Doe, John Doe, JohnDoe, Sales, 01-Mar-21, Commercial, Commercial, 4, 8, Central, Associate, 2012
Jake, Doe, Jake Doe, JakeDoe, Sales, 22-Feb-21, Commercial, Commercial, 2, 2, West, Associate, 2019'`

const tableNoHeader = csvData
  .split('\n').slice(1) 
  .map(line =>
    {  //  0          1         2         3    4     5       6          7          8            9            10      11        12
    let [ FirstName, LastName, FullName, Key, Role, weekOf, UnitType1, UnitType2, UnitsSales1, UnitsSales2, region, Position, Hire]
        = line.split(/, |,/)
    return ({ region, weekOf, sales : (+UnitsSales1) + (+UnitsSales2) })
    })     
  .reduce((res,{region,weekOf,sales}) =>
    {
    res[region] = res[region] || []
    let regWeek = res[region].find(x=>x.weekOf === weekOf )
    if (!regWeek) res[region].push({ weekOf, sales })
    else          regWeek.sales += sales
    return res
    }, {})
console.log( tableNoHeader )
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

denis hebert
denis hebert

Reputation: 130

To add a cumulation per date: before your push, we need to check if row[5] is already listed as a weekOf in the region...

const tableNoHeader = table
          .split('\n')
          .map(line => line.split(','))
          .slice(1)
          .reduce((region, row) => {
            const region1 = region[row[10]] || [],
            sale1 = parseFloat(row[8]) >= 0 && parseFloat(row[9]) >= 0 ? parseFloat(row[8]) + parseFloat(row[9]) : "";

            for(var i = 0; i < region1.length; i++) {
              if region1[i].weekOf === row[5] {
                region1[i].sales += sale1; // make sure it's numeric if not ""
                region1[i].sales = region1[i].sales ? + region1[i].sales : "";
                break;
              }
            }
            if(i === region1.length) region1.push({
              weekOf: row[5],
              sales: sale1
            });
            region[row[10]] = region1;
            return region;
          }, {});

 

Upvotes: 1

Related Questions