0

I have an array of objects like this:

arrayOfObjs = [{1:"h"}, {1:"h"}, {2:"h"}, {3:"ha"}, {4:"haa"}, {4:"haa"}, {4:"haa"}]

I'd like to count the occurrence of each object, and get the result back in a sorted, iterable data structure, like this:

{
  {4:"haa"}: 3,
  {1:"h"}: 2,
  {2:"h"}: 1,
  {3:"ha"}: 1
}

The keys can even be in arrays. I tried using Lodash's countBy function on arrayOfObjs. However, this simply resulted in

{[object Object]:5}

Any libraries/functions I can use to get this job done? Something similar to Python's Counter

UPDATE

As an alternative, I tried to organize my array like this:

array = [[1,"h"], [1,"h"], [2,"h"], [3,"ha"], [4,"haa"], [4,"haa"], [4,"haa"]];

Again used Lodash's countBY function, and my result was:

{1,h: 2, 2,h: 1, 3,ha: 1, 4,haa: 3}

Which is a bit better, but I now I have to use regular expressions to split apart each key of the object, since "1, h" is a string. Not ideal :(

Ideally, I'd like my keys to be either objects, or arrays, or something of the sort.

10
  • You mean you want to count occurrences of objects with the same properties as each other? Because in your sample array each object occurs only once: the first two array elements are not the same object, they're two distinct objects that happen to have the same property defined. Commented Feb 7, 2016 at 6:30
  • Try comparing JSON.stringify strings Commented Feb 7, 2016 at 6:30
  • Unfortunately, your keys are not going to be able to be objects, or anything other than strings for that matter. JavaScript objects are hash tables, and the hash table keys are strings. JavaScript doesn't allow for primitive values as keys either, so even if you set your object key to a number, it will still be converted to a string. The suggestion of using JSON mostly alleviates this concern, because you could always deserialize the keys back to objects later. Commented Feb 7, 2016 at 6:57
  • @JacobHeater , do you know if deserializing each key is time expensive? When I loop through my result, I'd have to deserialize each key, per loop. Commented Feb 7, 2016 at 7:03
  • 1
    @user5792950, I was thinking something like this, [{ count: 3, key: { 4: 'ha' } }, ..., ..., { count: 2, key: { 1: 'h' } }]. The array would contain objects that store metadata about the counts and the keys could still be in their object form. Commented Feb 7, 2016 at 7:36

5 Answers 5

1

Shameless Plug:

I am working on a library called Pro.js that has a collections module that does all sorts of neat things. The enumerable class has a .groupBy() method that would be particularly useful here.

var arrayOfObjs = [{1:"h"}, {1:"h"}, {2:"h"}, {3:"ha"}, {4:"haa"}, {4:"haa"}, {4:"haa"}];
var enumerable = pro.collections.asEnumerable(arrayOfObjs);
var grouped = enumerable.groupBy(function(o) {
    return JSON.stringify(o);
});
var composites = grouped.select(function(g) {
    return {
        key: g[0],
        count: g.length,
        group: g
    };
});
var output = composites.toArray();

You can go to the Pro.js GitHub Page and use your developer tools to test out the library. Run the code snippet that I posted in the answer on the page and see if it produces a likeable result for you.

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

Comments

1

arrayOfObjs = [{1:"h"}, {1:"h"}, {2:"h"}, {3:"ha"}, {4:"haa"}, {4:"haa"}, {4:"haa"}];

var hash = {};
arrayOfObjs.forEach(function(item){
    var key = JSON.stringify(item);
    if (hash[key]) {
        hash[key]++;
    } else {
        hash[key] = 1;
    }
});
console.log(hash);

var hash2 = {};
arrayOfObjs.forEach(function(item){
    var key = JSON.stringify(item);
    if (hash2[key]) {
        hash2[key]++;
    } else {
        hash2[key] = 1;
    }
});
for (key in hash2) {
    val = hash2[key];
    console.log(key, val);
}

Note, that insted of hash[key] you could use hash[item], you just won't see it the way you expect by console.log(hash)

2 Comments

I think he wants to count object not key's
@RIYAJKHAN, I did that, it's just the "name" of my variable, because it acts as a key in the hash I count them in. See my edit, I made the 2 examples clear
1

I decided this task using _.countBy, _.map and _.reduce

arrayOfObjs = [{1:"h"}, {1:"h"}, {2:"h"}, {3:"ha"}, {4:"haa"}, {4:"haa"}, {4:"haa"}];

var a = _.countBy(arrayOfObjs, function (obj) {
    return _.map(obj, function (value, key) {
    return key + ' ' + value;
  });
})

b = _.reduce(a, function (result, value, key) {
    var splittedKey = key.split(' ');
  var newObj = {};

  newObj[splittedKey[0]] = splittedKey[1];

  var newKey = JSON.stringify(newObj)
  var resultObj = {};

  resultObj[newKey] = value;
  result.push(resultObj)

  return result;
}, []);

console.log(b)

https://jsfiddle.net/tkv94whe/

Comments

0

You can try something like this:

var arrayOfObjs = [{1:"h"}, {1:"h"}, {2:"h"}, {3:"ha"}, {4:"haa"}, {4:"haa"}, {4:"haa"}]

var result = {};

arrayOfObjs.forEach(function(item){
  var objStr = JSON.stringify(item);
  result[objStr] = result[objStr]? ++result[objStr]: 1;
});
console.log(result);

Comments

-1

You can iterate over your array and use JSON.stringify() to convert objects to string and then compare them. Its simple hashmap technique that can be used then.

arrayOfObjs = [{1:"h"}, {1:"h"}, {2:"h"}, {3:"ha"}, {4:"haa"}, {4:"haa"}, {4:"haa"}];
    var result={}
    for(var i=0;i<arrayOfObjs.length;i++){
        if(!result[JSON.stringify(arrayOfObjs[i])]){
        result[JSON.stringify(arrayOfObjs[i])]=1;
      } else {
        result[JSON.stringify(arrayOfObjs[i])]=result[JSON.stringify(arrayOfObjs[i])]+1;
      }
    }
    console.log(result);

https://jsfiddle.net/xv22v72v/

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.