Create an array of sub-arrays with the value of an element and the number of times it has repeated in JavaScript

139 views Asked by At

I'm trying to take an array (for an example, an array of years) and then make a new array of sub-arrays which tells, firstly, the unique element in the original array and, secondly, how many time it was repeated.

For example, lets say I start of with an array of numbers [1999, 1999, 2000, 2005, 2005, 2005, 2015]

I would like my function to return an array like [[1999, 2], [2000, 1], [2005, 3], [2015, 1] ]
because the year 1999 was repeated twice, the year 2000 was was not repeated, the year 2005 was repeated three times, etc.

I can successfully make a new array that removes the duplicates, but Im getting some weird behavior when it comes to making my sub-arrays.

EDIT

Here was my own faulty solution, in case anyone wants to point out what i did wrong.

var populateYearsList = function(yearsDuplicate){

var uniqueYears = [];
for (var i=0; i < yearsDuplicate.length; i++){
 if(uniqueYears.indexOf(yearsDuplicate[i]) == -1){
  uniqueYears.push(yearsDuplicate[i])
} else {
  console.log("duplicate found") };
}
 console.log (uniqueYears)
};

I ran into the problem of trying to change uniqueYears.push(yearsDuplicate[i]) into uniqueYears.push([ yearsDuplicate[i], 1 ]) and then trying to replace my console.log into some sort of incremented counter.

4

There are 4 answers

4
TaoPR On BEST ANSWER

It is as easy as:

var input = [1999, 1999, 2000, 2005, 2005, 2005, 2015];

var uniq = [];
input.forEach(function(n){
    if (uniq.indexOf(n)<0) 
        uniq.push(n);
});

var output = uniq.map(function(n){
    return [n, input.filter(function(m){ return m == n }).length]
});

Quick explanation how it works

Given the input array, map its unique version to the new array with this mapping:

element ---> [ element, the number of occurrences in the original array ]

EDIT NOTE:: FIXED the previous solution which might introduced duplicate element.

1
Stefan Dimov On

This is how I would do it:

var input = [1999, 1999, 2000, 2005, 2005, 2005, 2015];

function numberOfOccurancesArray (input) {
    var result = {};

    for (var i = 0; i < input.length; i++) {

        var currentYear = input[i];

        // if there is an element with the name of the currentYear
        if (result[currentYear]) {

            // increace its prop `count` with 1
            result[currentYear].count += 1;

        } else {

            // if not present, create it
            result[currentYear] = {
                year: currentYear,
                count: 1
            }
        }
    }

    return result;
}

Here is sample code : JsFiddle

2
Wojciech Grzebieniowski On
var years = [1999, 1999, 2000, 2005, 2005, 2005, 2015];

var occurences = [];

for(var i = 0; i < years.length; i++ ) {
    var year = years[i];
    if(typeof occurences[year] === 'undefined') {
        occurences[year] = 1;
    } else {
        occurences[year]++;   
    }
}

occurences = occurences.map(function(occurences, year) {
    return [year, occurences];
});

console.log(occurences);

EDIT: Much faster solution

    var results = [];
    var uniq = [];
    var counts = [];
    var i = 0;

    for (i; i < years.length; i++) {
        var year = years[i];
        var indexOf = uniq.indexOf(year);
        if (indexOf < 0) {
            uniq.push(year);
            counts[uniq.length - 1] = 1;
        } else {
            counts[indexOf] += 1;
        }
    }

    i = 0;

    for (i; i < uniq.length; i++) {
        results.push([uniq[i], counts[i]]);
    }

    return results;
1
NG. On

If you want to play with functional paradigms, reduce it to a dictionary and then map the keys to a tuple.

var yearToCounts = input.reduce(function(counts, year) {
    if (year in counts) {
        counts[year]++;
    } else {
        counts[year] = 1;
    }
    return counts;
}, {});

return Object.keys(yearToCounts).map(function(year) {
    return [year, yearToCounts[year]];
});