3

I have two arrays

var arrayA = ["a", "a", "b", "b", "a", "c"];
var arrayB = [10, 20, 3, 2, 20, 5];

As you can see, arrayA[0], arrayA[1], arrayA[4] have an same elements (arrayA[2], arrayA[3] same too).

So based on above example, I want arrayB[0], arrayB[1], arrayB[4] will be summed up, and arrayB[2], arrayB[3] too.

expectation output

arrayA = ["a", "b", "c"];
arrayB = [50, 5, 5];

It's possible to sum the arrayB elements if arrayA have same elements based arrayA index? and is there an Lodash/Underscore function to do this?

Engkus Kusnadi
  • 2,386
  • 2
  • 18
  • 40
  • 1
    Have you tried anything? – Rajesh Nov 24 '17 at 09:09
  • 4
    Possible duplicate of [Remove duplicate values from JS array](https://stackoverflow.com/questions/9229645/remove-duplicate-values-from-js-array) – Pratansyah Nov 24 '17 at 09:11
  • 2
    @Pratansyah Though I really appreciate the effort, this is not duplicate. OP wants to sum values in second array and make it unique. – Rajesh Nov 24 '17 at 09:17

8 Answers8

6

You could use an object for the indices and maintain the values.

var arrayA = ["a", "a", "b", "b", "a", "c"],
    arrayB = [10, 20, 3, 2, 20, 5],
    indices = Object.create(null),
    groupedA = [],
    groupedB = [];
    
arrayA.forEach(function (a, i) {
    if (!(a in indices)) {
        groupedA.push(a);
        indices[a] = groupedB.push(0) - 1;
    }
    groupedB[indices[a]] += arrayB[i];
});

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

Version which mutates the original arrays.

var arrayA = ["a", "a", "b", "b", "a", "c"],
    arrayB = [10, 20, 3, 2, 20, 5],
    indices = Object.create(null),
    i = 0;

while (i < arrayA.length) {
    if (!(arrayA[i] in indices)) {
        indices[arrayA[i]] = i++;
        continue;
    }
    arrayB[indices[arrayA[i]]] += arrayB.splice(i, 1)[0];
    arrayA.splice(i, 1);
}

console.log(arrayA);
console.log(arrayB);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Wow ... `groupedB.push(0) - 1;` , this is really nice way to do it :) – Pranav C Balan Nov 24 '17 at 09:23
  • `push` returns the length of the array after pushing. – Nina Scholz Nov 24 '17 at 09:25
  • I'm a bit confused on this statement `indices[a] = groupedB.push(0) - 1;` , any more explain? – Engkus Kusnadi Nov 27 '17 at 02:50
  • @EngkusKusnadi, it pushes the value zero at the end of `groupedB`, and because `push` returns the new length of the array, you get the index of the last inserted item with a decrement of `- 1`. the result is a value of zero at the index in the hash table `indices`. in the next line, the index is used to update the sum of the same item at the index of the hash table. – Nina Scholz Nov 27 '17 at 07:15
2

Here's a solution using lodash:

[arrayA, arrayB] = _(arrayA)
    .zip(arrayB)
    .groupBy(0)
    .mapValues( grp => _.sumBy(grp,1))
    .thru(obj => [_.keys(obj), _.values(obj)])
    .value();

zip will associate each element in arrayA with the corresponding element in arrayB e.g. [ ['a', 10], ['a', 20], ...]

We then groupBy the value in position 0 giving an object something like:

{
   a: ['a', 10], ['a', 20], ['a', 20'],
   b: ['b', 3] ...,
   c: ...
}

The values of each key are then mapped to the sum of the values in position 1 before finally returning the keys and the values in separate arrays.

Gruff Bunny
  • 27,738
  • 10
  • 72
  • 59
2

You can reduce both arrays into an ES6 Map, and then spread the keys for arrayA, and the values for arrayB:

const arrayA = ["a", "a", "b", "b", "a", "c"];
const arrayB = [10, 20, 3, 2, 20, 5];

const map = arrayA.reduce((m, c, i) => m.set(c, (m.get(c) || 0) + arrayB[i]), new Map());

const arrA = [...map.keys()];
const arrB = [...map.values()];

console.log(arrA);

console.log(arrB);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
1

Use Array#reduce method.

var arrayA = ["a", "a", "b", "b", "a", "c"];
var arrayB = [10, 20, 3, 2, 20, 5];

// reference to keep the index
var ref = {},
  // array for keeping first result
  res1 = [];


var res2 = arrayA
  // iterate over the first array
  .reduce(function(arr, v, i) {
    // check index presenet in the refernece object
    if (!(v in ref)) {
      // if not then define the index and insert  0 in the array(defining the new index)
      arr[ref[v] = arr.length] = 0;
      // push value into the array( for unique value )
      res1.push(v);
    }
    // update the element at the index
    arr[ref[v]] += arrayB[i];
    // return the array reference
    return arr;
    // initialize initial value as an empty array to keep result
  }, [])

console.log(res1, res2);
Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
1

You can compute sums of all elements in arrayB that corresponds to each element in arrayA, store these sums in an object and use Object.values to get an array of the sums.

var arrayA = ["a", "a", "b", "b", "a", "c"];
var arrayB = [10, 20, 3, 2, 20, 5];

var sum = {};

arrayA.forEach((l, index) => {
    sum[l] = (sum[l] || 0) + arrayB[index];
});

var res = Object.values(sum);

console.log(res);

And it can be done even shorter with array.prototype.reduce:

var arrayA = ["a", "a", "b", "b", "a", "c"];
var arrayB = [10, 20, 3, 2, 20, 5];

var res = Object.values(arrayA.reduce((m, l, index) => {
    m[l] = (m[l] || 0) + arrayB[index];
    return m;
}, {}));

console.log(res);
Faly
  • 13,291
  • 2
  • 19
  • 37
1

With an intermediary "result" object:

var arrayA = ["a", "a", "b", "b", "a", "c"];
var arrayB = [10, 20, 3, 2, 20, 5];
var result = {};

for (var i = 0, max = arrayA.length; i < max; i++) {
    if (!result[arrayA[i]]) {
        result[arrayA[i]] = 0;
    }

    result[arrayA[i]] += arrayB[i];
}

var keys = Object.keys(result);

arrayA = [];
arrayB = [];
for (var i = 0, max = keys.length; i < max; i++) {
    arrayA.push(keys[i]);
    arrayB.push(result[keys[i]]);
}
dferenc
  • 7,918
  • 12
  • 41
  • 49
1
let _ = require('underscore');

var arrayA = ["a", "a", "b", "b", "a", "c"];
var arrayB = [10, 20, 3, 2, 20, 5];

let res = {};
_.each(arrayA, (item, key) => {

  if (! res[item]) {
    res[item] = arrayB[key];
  } else {
    res[item] = res[item] + arrayB[key];
  }

});

arrayA = [];
arrayB = [];

_.each(res,(value,key) => {
  arrayA.push(key);
  arrayB.push(value);
});

console.log(arrayA);
console.log(arrayB);
Ayan
  • 8,192
  • 4
  • 46
  • 51
1

First fill the dict and then fill de arrays with the keys and values

let arrayA = ["a", "a", "b", "b", "a", "c"];
let arrayB = [10, 20, 3, 2, 20, 5];

let result = {};

for (let i=0; i < arrayA.length; i++ ){
    let valueB = 0;
    if (arrayB.length > i) {
        valueB = arrayB[i];
    }

    if (result.hasOwnProperty(arrayA[i])) {
      result[arrayA[i]] += valueB;
    }
    else {
      result[arrayA[i]] = valueB;
    }
}

let resultA = [];
let resultB = [];
for (let k in result) {
    resultA.push(k);
    resultB.push(result[k]);
}
console.log(resultA);
console.log(resultB);
Aleix Soler
  • 91
  • 2
  • 7