0

I'm looking for an effective way to count the occurrence of elements. I read the data in a loop, and in every step I want to increase the right object element in the result array, or create a new one, if it isn't available yet.

I have to work with a lot of data, so I need a quick solution. Here is a working version:

var hugeDataObject = [
    {id: '1234', dark: true},
    {id: '5678', dark: true},
    {id: '91011', dark: true},
    {id: '91011', dark: false}
];
var ids = [];
var darks = [];
var allIds = [];
var allDarks = [];
  hugeDataObject.forEach(function(attrs) {
    var index = allIds.indexOf(attrs.id);
    if(index >= 0) ids[index].amount += 1;
    else {
      ids.push({type: attrs.id, amount: 1}); 
      allIds.push(attrs.id);
    }

    var index = allDarks.indexOf(attrs.dark);
    if(index >= 0) darks[index].amount += 1;
    else {
      darks.push({type: attrs.dark, amount: 1}); 
      allDarks.push(attrs.dark);
    }
  });

Fiddle But I have more types, what I need to count, so there is too much variable.

The result:

ids = [
  {type: '1234', amount: 1},
  {type: '5678', amount: 1},
  {type: '91011', amount: 2}
]

darks = [
  {type: true, amount: 3},
  {type: false, amount: 1}
]

(If you use loDash, it's ok)

Thanks in advance!

kree
  • 440
  • 1
  • 9
  • 26
  • 1
    Where data have been stored? – vborutenko Aug 01 '14 at 07:41
  • 3
    Without knowing what you have so far, or where the data comes from and what structure it has, any answer will be nothing but a lucky guess. – UweB Aug 01 '14 at 07:41
  • Please show us more code: where is the data coming from? where are you storing the "occurrences"? do you need to count only a certain occurrence or many of them? – briosheje Aug 01 '14 at 07:42
  • possible duplicate of [Convert JSON string to array of JSON objects in Javascript](http://stackoverflow.com/questions/4375537/convert-json-string-to-array-of-json-objects-in-javascript) – Luca Davanzo Aug 01 '14 at 07:45
  • Side note. If `hugeDataObject` is really huge you should better do this grouping on the server side. BTW plain old for loop is faster than `forEach` since the later has overhead on function call and `hasOwnProperty` check. – Yury Tarabanko Aug 01 '14 at 07:57

4 Answers4

1

How about a simpler structure to store:

var objects = {};
objects['id1234'] = 384;
objects['id5678'] = 955;
objects['id91011'] = 1510;

/* increment */
objects['id1234']++;
Wolph
  • 78,177
  • 11
  • 137
  • 148
  • I did this in the first time, but I need to create a table from it, with angularJS directive, so I need a simple table, not an object. – kree Aug 01 '14 at 07:50
1
var counter = {};
hugeDataObject.forEach(function(attrs) {
    if (counter[attrs.id]) {
        counter[attrs.id]++;
    }
    else {
        counter[attrs.id] = 1;
    }
});

Or if you need array:

var counts = [];
var indexMap = {};

var i = 0;
indexMap[0] = -1;

hugeDataObject.forEach(function(attrs) {

    var index = indexMap[attrs.id];

    if (index == undefined) {
        indexMap[attrs.id] = i;
        counts[i] = { id: attrs.id, amount: 1 };
        i++;
    }
    else {
        var existingCounter = counts[index];
        existingCounter.amount++;
    }
});
Sergey Metlov
  • 25,747
  • 28
  • 93
  • 153
0

If I understand your point, then you try use this:

 var ids = [];
  var allIds = [];
  hugeDataObject.forEach(function(attrs) {
    var index = allIds.indexOf(attrs.id);
    if(index >= 0){
      ids[index].amount = ids[index].amount + 1;

    } else {
      ids.push({type: attrs.id, amount: 1}); 
      allIds.push(attrs.id);
      // Here first should check is this type available, 
      // after create it or increase the amount
    }
  });

  console.log(ids);
AmanVirdi
  • 1,667
  • 2
  • 22
  • 32
  • This algorithm has very high complexity for such task. O(n^2) – Sergey Metlov Aug 01 '14 at 07:54
  • It is work well, thank you! But I don't know is it the most effective way? Because I don't need to count the ids, there are other parameters, what I have to count, and with your solution, I have to create one more variable for everythink, what I want to count... – kree Aug 01 '14 at 07:58
  • @SergeyMetlov It is `O(n*m)` where `m` is the number of groups. But generally you are right. Yours is actually `O(n)`. – Yury Tarabanko Aug 01 '14 at 07:58
  • Thanks you all, I will research more. – AmanVirdi Aug 01 '14 at 08:01
  • @YuryTarabanko yep, you're right. Anyway uadratic dependence. – Sergey Metlov Aug 01 '14 at 08:10
  • @AmanVirdi, I updated my question depend on your answer. I hope now it's clear, what I asked again. – kree Aug 01 '14 at 08:18
-1

It's not too simple, but I got it.

var getObjectBy = function(base, id, array) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i][base] === id) return array[i];
    }
    return null;
};

var hugeDataObject = [
    {id: '1234', dark: true},
    {id: '5678', dark: true},
    {id: '91011', dark: true},
    {id: '91011', dark: false}
];
var ids = [];
var darks = [];
hugeDataObject.forEach(function(attrs) {
    var index = getObjectBy('type', attrs.id, ids);
    if (index === null) ids.push({type: attrs.id, amount: 1});
    else index.amount += 1;

    var index = getObjectBy('type', attrs.dark, darks);
    if (index === null) darks.push({type: attrs.dark, amount: 1});
    else index.amount += 1;
});

Updated Fiddle

Perhaps it isn't too pretty, but I think effective. If you know a better way, write it, and I will accept that!

Thanks your answers guys!

kree
  • 440
  • 1
  • 9
  • 26