Home > Enterprise >  How to transform a For Loop into Reduce checking names and sum rows?
How to transform a For Loop into Reduce checking names and sum rows?

Time:10-18

Given the following array, I need to reduce it by employee function names and also sum a few rows.

Reduce if Row[1] is equal with any other, and sum Row[2] and Row[5].

example array

[ 
  [ 20, 'AJUDANTE GERAL ', 2, 'HH', 6.36, 12.72, '', '' ],
  [ 20, 'AJUDANTE GERAL ', 8, 'HH', 6.36, 50.88, '', '' ],
  [ 20, 'AJUDANTE GERAL ', 0.15, 'HH', 6.36, 0.954, '', '' ],
  [ 20, 'AJUDANTE GERAL ', 8, 'HH', 6.36, 50.88, '', '' ],
  [ 125, 'CALDEREIRO', 8, 'HH', 13.05, 104.4, '', '' ],
  [ 0, 'ISOLADOR', 2, 'HH', 10.68, 21.36, '', '' ],
  [ 0, 'ISOLADOR', 8, 'HH', 10.68, 85.44, '', '' ],
  [ 0, 'ISOLADOR', 0.15, 'HH', 10.68, 1.6019999999999999, '', '' ],
  [ 585, 'PINTOR', 2, 'HH', 10.91, 21.82, '', '' ] 
]

result expected

[
  [ 20, 'AJUDANTE GERAL ', 18.15, 'HH', 6.36, 115.434, '', '' ],
  [ 125, 'CALDEREIRO', 8, 'HH', 13.05, 104.4, '', '' ],
  [ 0, 'ISOLADOR', 10.15, 'HH', 10.68, 108.402, '', '' ],
  [ 585, 'PINTOR', 2, 'HH', 10.91, 21.82, '', '' ]
]

I was able to achieve this using a few for loops which I believe it is not the real deal, since I am changing values during the loop. It is working, however, I would like to understand how could I do it with reduces and maps.

// sheetMapped is the array with all data duplicated
// uniqueRows is where I am keeping only the unique values with the sum values

let uniqueRows = [];
for (let i = 0; i < sheetMapped.length; i  = 1) {
  let row = sheetMapped[i];
  let found = false;

  for (let j = 0; j < uniqueRows.length; j  = 1) {
    let rowUniqueTest = uniqueRows[j];

    if (row[1] === rowUniqueTest[1]) {
      found = true;
      uniqueRows[j][2]  = row[2];
      uniqueRows[j][5]  = row[5];
      break;
    }
  }
  if (!found) {
    uniqueRows.push(row);
  }
}

I already tried a few examples using Array.from, set Maps, reduces, but they were a bit hard to understand since I am working with more data in array and not just key/value pairs.

Thanks in advance

CodePudding user response:

This can be done with a fairly standard 'group by' operation using reduce().

The snippet below uses a Map as it maintains insertion order where as an object sorts numeric properties. The resulting Map is converted back to an array using Array.from() called on the Map.values()

const input = [ [ 20, 'AJUDANTE GERAL ', 2, 'HH', 6.36, 12.72, '', '' ], [ 20, 'AJUDANTE GERAL ', 8, 'HH', 6.36, 50.88, '', '' ], [ 20, 'AJUDANTE GERAL ', 0.15, 'HH', 6.36, 0.954, '', '' ], [ 20, 'AJUDANTE GERAL ', 8, 'HH', 6.36, 50.88, '', '' ], [ 125, 'CALDEREIRO', 8, 'HH', 13.05, 104.4, '', '' ], [ 0, 'ISOLADOR', 2, 'HH', 10.68, 21.36, '', '' ], [ 0, 'ISOLADOR', 8, 'HH', 10.68, 85.44, '', '' ], [ 0, 'ISOLADOR', 0.15, 'HH', 10.68, 1.6019999999999999, '', '' ], [ 585, 'PINTOR', 2, 'HH', 10.91, 21.82, '', '' ], ];

const result = Array.from(
  input
    .reduce((a, row) => {
      if (!a.has(row[1])) {
        a.set(row[1], [...row]);
      } else {
        const _row = a.get(row[1]);
        _row[2]  = row[2];
        _row[5]  = row[5];
      }

      return a;
    }, new Map())
    .values()
);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

with an array as accumulator in reduce this is a piece of cake take a look at below code

var data = [ 
    [ 20, 'AJUDANTE GERAL ', 2, 'HH', 6.36, 12.72, '', '' ],
    [ 20, 'AJUDANTE GERAL ', 8, 'HH', 6.36, 50.88, '', '' ],
    [ 20, 'AJUDANTE GERAL ', 0.15, 'HH', 6.36, 0.954, '', '' ],
    [ 20, 'AJUDANTE GERAL ', 8, 'HH', 6.36, 50.88, '', '' ],
    [ 125, 'CALDEREIRO', 8, 'HH', 13.05, 104.4, '', '' ],
    [ 0, 'ISOLADOR', 2, 'HH', 10.68, 21.36, '', '' ],
    [ 0, 'ISOLADOR', 8, 'HH', 10.68, 85.44, '', '' ],
    [ 0, 'ISOLADOR', 0.15, 'HH', 10.68, 1.6019999999999999, '', '' ],
    [ 585, 'PINTOR', 2, 'HH', 10.91, 21.82, '', '' ] 
]



data = data.reduce((a,e)=>{
        let sInd = a.findIndex(each=>each.indexOf(e[1]) != -1)
        if(sInd >= 0){ // if entry added already
            a[sInd][2]  = e[2]
            a[sInd][5]  = e[5]
        }
        else{a.push(e)} // if new entry
        return a
    },[])

console.log(data.join("\n"))
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

If row and col are fixed, You can use below sample code. Merge as an object and get all values.

const data = [
  [20, "AJUDANTE GERAL ", 2, "HH", 6.36, 12.72, "", ""],[20, "AJUDANTE GERAL ", 8, "HH", 6.36, 50.88, "", ""],[20, "AJUDANTE GERAL ", 0.15, "HH", 6.36, 0.954, "", ""],[20, "AJUDANTE GERAL ", 8, "HH", 6.36, 50.88, "", ""],
  [125, "CALDEREIRO", 8, "HH", 13.05, 104.4, "", ""],
  [0, "ISOLADOR", 2, "HH", 10.68, 21.36, "", ""],[0, "ISOLADOR", 8, "HH", 10.68, 85.44, "", ""],[0, "ISOLADOR", 0.15, "HH", 10.68, 1.6019999999999999, "", ""],[585, "PINTOR", 2, "HH", 10.91, 21.82, "", ""],
];

const map = data.reduce((m, row) => {
  const id = row[0];
  if (id in m) {
    m[id][2]  = row[2];
    m[id][5]  = row[5];
  } else {
    m[id] = row;
  }
  return m;
}, {});

console.log(Object.values(map));
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related