theamateurdataanalyst
theamateurdataanalyst

Reputation: 2834

Creating a mapping of duplicates in array in JavaScript

I am trying to create a function that creates an object and counts the number duplicates per number in an array. For example if I have an array that is [1,2,2,2,3,3] my function should return 3 because there are two duplicates of 2 and one duplicate of 3. So I wrote a function that I thought was clever. I decided to create a mapping of frequences of each element. By setting the creation of each new property i.e. unique number in the array equal to -1. For some reason when I do this I get property values that are all equal to zero. I am getting two different sets of results from the two functions below.

function DistinctListV1(arr) { 
  var mapping = {};
      for(var i = 0; i < arr.length; i++){
        if(!mapping[arr[i]]){
          mapping[arr[i]] = 0; //Difference here
        }
          mapping[arr[i]] += 1;
      }         
return mapping
}


function DistinctListV2(arr) { 
  var mapping = {};
      for(var i = 0; i < arr.length; i++){
        if(!mapping[arr[i]]){
          mapping[arr[i]] = -1; //Difference here
        }
          mapping[arr[i]] += 1;
      }         
return mapping
}


DistinctListV1([1,2,2,3,3,3]) 
=> { '1': 1, '2': 2, '3': 3 }

DistinctListV2([1,2,2,3,3,3])   
=> { '1': 0, '2': 0, '3': 0 }  

Right now I am only concerned about creating an object with this mapping. Thanks for reading.

Edit:

=> DistinctListV3([1,2,2,3,3,3])

function DistinctListV3(arr) { 
  var mapping = {};
      for(var i = 0; i < arr.length; i++){
        if(!mapping[arr[i]]){
          mapping[arr[i]] = 100; //Difference here
        }
          mapping[arr[i]] += 1;
      }         
return mapping
}

DistinctListV3([1,2,2,3,3,3])

=> { '1': 101, '2': 102, '3': 103 }

Using this example, leads me to believe something is going on when I use -1 as the place to start incrementing.

Upvotes: 0

Views: 50

Answers (3)

Shai
Shai

Reputation: 7315

The problem you're running into is caused by this line:

if(!mapping[arr[i]]){

I think you're expecting the code inside that if to only run when mapping[arr[i]] doesn't exist yet. But the ! operator isn't strict: it will return true not just when mapping[arr[i]] is undefined, but also when mapping[arr[i]] is anything falsy, such as the number zero. This, of course, happens when you initialise the variable to -1 and then add 1 to it, causing all your mappings to be stuck at 0 indefinitely (they keep being set to -1 then incremented, meaning they are back to 0 and the if runs again and again, never getting above 0).

You want a more strict check:

if (typeof mapping[arr[i]] === 'undefined') {

Or

if (mapping.hasOwnProperty(arr[i])) {

Upvotes: 2

NanoWizard
NanoWizard

Reputation: 2164

!mapping[arr[i]] is true for undefined AND 0, which is why your first works and your second doesn't. The first time you add 1 to a property on mapping in DistinctListV2 it becomes 0, then the next time it finds the same number, !mapping[arr[i]] is true, so it sets that property to -1 again.

The fix is simple:

function DistinctListV2(arr) { 
  var mapping = {};
      for(var i = 0; i < arr.length; i++){
        if(mapping[arr[i]] === undefined){ // Check for undefined, not 'falsey'
          mapping[arr[i]] = -1;
        }
          mapping[arr[i]] += 1;
      }         
return mapping
}

Upvotes: 0

Michael Voznesensky
Michael Voznesensky

Reputation: 1618

What if you just dynamically create the object?

Something like:

var counterObject = {};
var duplicateCounter = 0;
for (var i = 0; i < array.length; i ++ ){
    var item = array[i];
    if (!counterObject[item]) {
       counterObject[item] = 'placeholder';
    } else {
       duplicateCounter++
    }
}

I did not test it, but the flow is: loop through array, grab item at i. Item at i is checked against the object. If it is there, then it must be a duplicate, so we increment the duplicate counter. If not, we assign some arbitrary value with the item name as the key, so that when we encounter it again we can increment. If you wanted to also see how many of each, you can set the 'placeholder' to 0, and then in the else {} increment hte count of that value in the object.

Upvotes: 0

Related Questions