32

I am attempting to change a program of mine from Python to Javascript and I was wondering if there was a JS function like the Counter function from the collections module in Python.

Syntax for Counter

from collection import Counter
list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a']
counter = Counter(list)
print counter

output

Counter({'a':5, 'b':3, 'c':2})
1

10 Answers 10

29

DIY JavaScript solution:

var list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];

function Counter(array) {
  var count = {};
  array.forEach(val => count[val] = (count[val] || 0) + 1);
  return count;
}

console.log(Counter(list));

JSFiddle example

Update:

Alternative that uses a constructor function:

var list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];

function Counter(array) {
  array.forEach(val => this[val] = (this[val] || 0) + 1);
}

console.log(new Counter(list));

JSFiddle example

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! I added an alternative that uses a constructor function and the new keyword.
super cooooooool!
10

You can use Lo-Dash's countBy function:

var list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];
console.log(_.countBy(list));

JSFiddle example

2 Comments

console.log(_.countBy([4,6,5,8,8,9,7,8])) produces "_ is not defined"
You need to include the lodash lib
5

I know I'm late but in case if someone is looking at this in 2020 you can do it using reduce, for example:

const counter = (list) => {
  return list.reduce(
    (prev, curr) => ({
      ...prev,
      [curr]: 1 + (prev[curr] || 0),
    }),
    {}
  );
};

console.log(counter([1, 2, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 1, 0]));
// output -> { '0': 1, '1': 6, '2': 2, '3': 1, '4': 1, '5': 1, '6': 1, '7': 1 }

more advance example with a callback function and context binding

const data = [1, 2, 3, 4, 5];

const counter = (list, fun, context) => {
  fun = context ? fun.bind(context) : fun;
  return list.reduce((prev, curr) => {
    const key = fun(curr);
    return {
      ...prev,
      [key]: 1 + (prev[key] || 0),
    };
  }, {});
};


console.log(counter(data, (num) => (num % 2 == 0 ? 'even' : 'odd')));
// output -> { odd: 3, even: 2 }

Comments

3

There is also pycollections.js, which works on Node and in client-side JS.

Example:

var collections = require('pycollections');
var counter = new collections.Counter([true, true, 'true', 1, 1, 1]);
counter.mostCommon(); // logs [[1, 3], [true, 2], ['true', 1]] 

Comments

3

In Python, the Counter also has add and update methods, which are used quite commonly. So a better solution would be this:

function Counter(array) {
    this.add = (val) => {
        this[val] = (this[val] || 0) + 1;
    };
    this.update = (array) => {
        array.forEach((val) => this.add(val));
    };
    this.update(array);
}

// Example usage
let myCounter = new Counter([1, 2, 2])
myCounter.update([3, 3, 3])
myCounter.add(4)
console.log(myCounter)

Comments

1

For those who want a pure JavaScript solution:

function countBy (data, keyGetter) {
  var keyResolver = {
    'function': function (d) { return keyGetter(d); },
    'string': function(d) { return d[keyGetter]; },
    'undefined': function (d) { return d; }
  };

  var result = {};

  data.forEach(function (d) {
    var keyGetterType = typeof keyGetter;
    var key = keyResolver[keyGetterType](d);

    if (result.hasOwnProperty(key)) {
      result[key] += 1;
    } else {
      result[key] = 1;
    }
  });

  return result;
}

Therefore:

list1 = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];
console.log(countBy(list1));  // {'a':5, 'b':3, 'c':2}

list2 = ['abc', 'aa', 'b3', 'abcd', 'cd'];
console.log(countBy(list2, 'length'));  // {2: 3, 3: 1, 4: 1}

list3 = [1.2, 7.8, 1.9];
console.log(countBy(list3, Math.floor));  // {1: 2, 7: 1}

Comments

1

How about this pure functional way:

let list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];

function counter(array) {
    return array.reduce((acc, value, index) => {
        acc[value] = value in acc ? acc[value]  + 1: 1
        return acc;
    }, {});
}

Fiddle Link

Comments

0

Here is a simple and easy to read solution:

 const word1 = "tangram"
    const dict1 = {}
    for (let char of word1){
     console.log(char)
     if (dict1[char]){
       dict1[char] += 1
       }else{
     dict1[char]= 1
     }
    }

enter image description here

enter image description here

Comments

0

This is my solution with explicit function calls

let list = [4, 6, 5, 3, 3, 1];

function counter(list) {

  let count = function(n) {
    let cnt = 0;
    for (let v of list) {
      if (v === n) cnt++
    }
    return cnt
  }

  let [...listSet] = new Set(list);
  let cntr = {};
  for (let v of listSet) {
    cntr[v] = count(v)
  }
  return cntr

}

console.log(counter(list))

Comments

0

Another version ->

s = "naman";

const counter = (s, sMap = {}) => {
  [...s].map((el) => {
    sMap[el] = sMap[el] ? sMap[el] + 1 : 1;
  });
  return sMap;
};

const res = counter(s);
console.log(`res`, res);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.