3

Any native alternatives for going from:

const colorArray = ['red', 'green', 'green', 'blue', 'purple', 'red', 'red', 'black'];

to:

Object {
  "red": 3,
  "green": 2,
  "blue": 1,
  "purple": 1,
  "black": 1
}

in javascript??

const colorArray = ['red', 'green', 'green', 'blue', 'purple', 'red', 'red', 'black'];

function categorizeUnique(array) {
  const distinct_objects = {};
  const length = array.length;
  for(let i=0; i<length; i++) {
    const distinct_objects_keys = Object.keys(distinct_objects);
    const possible_index = distinct_objects_keys.indexOf(array[i]);
    if(possible_index === -1) {
      distinct_objects[array[i]] = 1;
    } else {
      distinct_objects[distinct_objects_keys[possible_index]]++;
    }
  }
  return distinct_objects;
}

const result = categorizeUnique(colorArray);
console.log(result);
That was my try to accomplish this but I'd like a native solution already built in.

Thanks for your precious effort and time!!

Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
Jhon
  • 135
  • 8

2 Answers2

6

Array.prototype.reduce() seems to be pretty close to what you're looking for:

const src = ['red', 'green', 'green', 'blue', 'purple', 'red', 'red', 'black'],

      result = src.reduce((acc,color) => (acc[color]=(acc[color]||0)+1, acc), {})
      
console.log(result)
.as-console-wrapper{min-height:100%;}
Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
  • didn't really understand how (acc,color) => (acc[color]=(acc[color]||0)+1, acc) works. Btw I have a little experience with reduce, the accumulated and current arguments. Please explain. – Jhon Sep 01 '20 at 10:19
  • 1
    @Jhon : I believe, its [shortcircuit OR evaluation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR#Short-circuit_evaluation) and [comma operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator) that confuses you. – Yevhen Horbunkov Sep 01 '20 at 10:23
  • 1
    @Jhon : in a nutshell, `acc[color]||0` is evalutated as `acc[color]` or `0` if former is `undefined` (upon first time crossing each specific color); `(acc[color]=(acc[color]||0)+1, acc)` is essentially the same as `acc[color] = acc[color]||0+1; return acc` – Yevhen Horbunkov Sep 01 '20 at 10:25
  • Be careful with `comma-operator` `->` [no-sequences rule](https://eslint.org/docs/rules/no-sequences) – Ele Sep 01 '20 at 10:51
2

Use .reduce:

const colorArray = ['red', 'green', 'green', 'blue', 'purple', 'red', 'red', 'black'];

let colorCount = colorArray.reduce((a, c) => ({ ...a, [c]: a[c] + 1 || 1}), {} );
      
console.log(colorCount);
Majed Badawi
  • 27,616
  • 4
  • 25
  • 48
  • The slight problem with this approach is that it re-creates unnecessarily accumulator object upon each iteration which [may slow down](https://jsbench.me/mxkejsqpzo/1) the code when input array is large enough. – Yevhen Horbunkov Sep 01 '20 at 10:17