1

I have an array like this, I want to count the frequency of each element

var arr = [1, 5, 7, -1];
function countArray (arr){
    var map = [];
    for (var i =0; i < arr.length ; i++){
        map[arr[i]]++;
    }
    console.log(map);  
}

The console.log prints [1: NaN, 5: NaN, 7: NaN, -1: NaN]

I expected it to print [1: 1, 5: 1, 7: 1, -1: 1]

I do not understand why I'm getting NaN

3
  • 1
    Before doing ++, you need to initialize the values to 0. Otherwise, you're doing null+1, which is NaN (not a number). You can solve this by adding that at the beginning of your for loop: if(!map.hasOwnProperty(arr[i])){ map[arr[i]] = 0; } Commented Apr 28, 2016 at 22:26
  • @JoshKG I'm a single mom learning programming. Commented Apr 28, 2016 at 22:45
  • 1
    Sorry, bad "Lego Movie" joke :) Commented Apr 28, 2016 at 23:14

4 Answers 4

4

Well, if it was the first occurance, then you would try to increment an undefined. So first check if it is undefined then assign 0, or increment it.

And you should use an Object, not an array. The object has a key and value whereas an Array is an ordered set of elements, accessed by their numeric index.

I'm editing this to explain that you can use an Array Object. If the value of the index is greater than largest index in the array, then it will be resized. However, I think an Object is better to use because in the future if you use some other type of key, (not a Number) then the code won't need any changes.

var arr = [1, 5, 7, -1];
function countArray (arr) {
    var map = {};
    for ( var i =0; i < arr.length ; i++ ){
        map[ arr[i] ] = typeof map[ arr[i] ]  === 'undefined' ? 1 : ++map[ arr[i] ];
    }
    console.log(map);  
}
Sign up to request clarification or add additional context in comments.

1 Comment

Alternatively: map[arr[i]] = (map[arr[i]] || 0 ) + 1.
2

Your function is fine but you can do it with array.reduce one liner:

var arr = [1, 5, 7, -1, 1,1];

var r = arr.reduce((ac, x) => { if (!ac[x]) ac[x] = 0;  return ac[x]++, ac},{});

document.write(JSON.stringify(r))

choose whatever you find more readable..

2 Comments

I just put my one-liner here so yours wouldn't be alone: xs.reduce((acc, x) => Object.assign(acc, { [x]: (acc[x] || 0) + 1 }), {});
Unless otherwise specified, please use ES5 syntax when answering questions like that, for maximum browser compatibility. Arrow functions (introduced with ECMAScript 2015) are not supported by all major browsers yet (IE 11, for example, which is the highest version of IE available on Windows 7, is still widely used).
2

A more explanatory version (JSBin) with reduce:

var arr = [1, 5, 7, -1];    

var count = arr.reduce(function(obj, next) {
  obj[next] = ++obj[next] || 1;
  return obj;
}, {});

Comments

0

You should check if array already contains key, you can use "in" to do that.

var arr = [1, 5, 7, -1, -1];
function countArray (arr){
    var map = [];
    for (var i =0; i < arr.length ; i++){
        if (arr[i] in map) map[arr[i]]++;
        else map[arr[i]] = 1;
    }
    console.log(map);  
}
countArray (arr)

Output:

[1: 1, 5: 1, 7: 1, -1: 2]

1 Comment

This will cause problems if an element is used that matches the name of a property in the Object prototype. If you're using in, you should filter the results by doing a hasOwnProperty check. I also can't recommend following the "inline" style of your conditionals given the OP is just learning.

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.