hmlee
hmlee

Reputation: 887

How to get count of elements in an array, when elements are unknown

So I'm trying to figure out how to generate an associative array that lists the elements of an array, and the number of times each element occurs, without knowing what the elements are beforehand.

As an example, let's say I have an array of animals: var animals = ['Rhino', 'Lion', 'Dog', 'Parrot', 'Parrot', 'Cat', 'Zebra', 'Rhino']

I'd like to generate an object that ultimately looks like:

{ 'Rhino': 2, 'Lion': 1, 'Dog': 1, 'Parrot': 2, 'Cat': 1, 'Zebra': 1 }

If I knew what the animals in the array were beforehand, I could of course do something like:

var animalsCount = {};

var numberOfRhinos = animals.filter(function(animal) {
   return animal == 'Rhino'
}).length;

animalsCount['Rhino'] = numberOfRhinos

to get an object like I'd like. The problem of course is that this becomes quite lengthy and repetitive depending on the number of animals. As well, if I don't know what each type of animal is I can't create the object this way. There must be a way to do this without knowing that information, but I'm stuck.

Upvotes: 16

Views: 2390

Answers (7)

Kishore Sahasranaman
Kishore Sahasranaman

Reputation: 4230

You can easily get it in two arrays as below.

var animals = ['Rhino', 'Lion', 'Dog', 'Parrot', 'Parrot', 'Cat', 'Zebra', 'Rhino'];

function foo(arr) {
    var a = [],
        b = [],
        prev;

    arr.sort();
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] !== prev) {
            a.push(arr[i]);
            b.push(1);
        } else {
            b[b.length - 1]++;
        }
        prev = arr[i];
    }
    return [a, b];
}

console.log(foo(animals));

Disclaimer : output array is alphabetically sorted.

Upvotes: 2

Ruan Mendes
Ruan Mendes

Reputation: 92274

Easiest way is to create a map, initializing (to 1) values in the array as a a property on that map. You can increment a property's value every time you see a property that is not undefined.

    function countObjs(arr) {
      // So the object doesn't inherit from Object.prototype and avoids property
      // name collisions
      var obj = Object.create(null);
      arr.forEach(function(item) {
        if (obj[item]) {
          obj[item]++;
        } else {
          obj[item] = 1;
        }
      });
      return obj;
    }
    var animals = ['Rhino', 'Lion', 'Dog', 'Parrot', 'Parrot', 'Cat', 'Zebra', 'Rhino'];
    console.log(countObjs(animals));
    /*
    Cat: 1
    Dog: 1
    Lion: 1
    Parrot: 2
    Rhino: 2
    Zebra: 1
    */

Upvotes: 19

zangw
zangw

Reputation: 48356

The countBy in the underscore may meet your requirement.

_.countBy(animals, function(n) { return n; })

output:

{ 'Rhino': 2, 'Lion': 1, 'Dog': 1, 'Parrot': 2, 'Cat': 1, 'Zebra': 1 }

Upvotes: 2

iScor
iScor

Reputation: 95

You can use library like lodash to get this result.

Otherwise you can iterate your array. Check if your animalsCount prototype contains the animal entry and increment or initialize value.

Upvotes: 1

rajuGT
rajuGT

Reputation: 6404

Just loop over the array elements with properties and store them in the object.

var animals = ['Rhino', 'Lion', 'Dog', 'Parrot', 'Parrot','Cat', 'Zebra', 'Rhino'];
var animalsCount = {};

for(var i = animals.length - 1; i >=0; i--) {
    var count = animalsCount[animals[i]];
   if(!count) count = 1;
   else count++; 
   animalsCount[animals[i]] = count;
}

console.log(animalsCount); 
//Outupt {Rhino: 2, Zebra: 1, Cat: 1, Parrot: 2, Dog: 1…}

//accessing particular animal count
animalsCount['Cat'];                 //outputs 1

Upvotes: 4

nicael
nicael

Reputation: 18997

Just generate a dictionary by looping trough the animals, then fill it looping through your animals again.

    var animals = ['Rhino', 'Lion', 'Dog', 'Parrot', 'Parrot', 'Cat', 'Zebra', 'Rhino'];
    var animals_dict={};
    for(var i=0;i<animals.length;i++){
        animals_dict[animals[i]]=0;
    }
    for(var i=0;i<animals.length;i++){
      animals_dict[animals[i]]=animals_dict[animals[i]]+1;
    }
    alert(JSON.stringify(animals_dict))

Upvotes: 5

PhilVarg
PhilVarg

Reputation: 4811

You can iterate over each element in the array, create a key in the counting object (associative arrays are called just called objects in JS) if one does not exists and set it to 1, or if it does exists add to the value.

animals.forEach(function(animal){
  var count;

  count = animalsCount[animal];

  if (count){
    animalsCount[animal] = count + 1;
  } else {
    animalsCount[animal] = 1;
  }  
})

Upvotes: 3

Related Questions