DEV Community

loading...
Cover image for Count Item Occurrences in an Array JavaScript Solution

Count Item Occurrences in an Array JavaScript Solution

hellodevworldblog profile image Hello Dev World Blog Originally published at hellodevworld.com ・4 min read

Link to Video

Happy day 7 of 365 Days of Coding! 1 week down 52 to go. A JavaScript solution for a function that counts how many times something shows up in an array. This can be a flat array or an array of arrays.

Disclaimer: there are MANY ways to solve this problem this is an answer that I would see or use in a coding interview and would accept as a proper answer

TLDR: Solution is at the bottom of the post

The Problem

Create a function that accepts an array and an item and counts the number of times that item shows up in the array. Do not ignore capitalization, punctuation, or spaces.

Examples:

      itemCounter(["hello", [["Hello", "hello"], [["Hello"]], "Hello", "world"]], "hello"); // 2

      itemCounter([["A", "A", "A", "A", "A", "a"],
        ["a", "A", "A", "A", "A", "A"],
        ["A", "a", "A", "A", "A", "A"],
        ["A", "A", "A", "a", "A", "A"]], "a"); // 4

      itemCounter([1, 2, [3], [4, 5], [4, [[6, 7], 4]]], 4); // 3

      itemCounter([1, 2, [3, 11], [4, 5], [4, [[6, 7], 4]]], 10) // 0
Enter fullscreen mode Exit fullscreen mode

The Solution

Lets write down what we will need to do

  • possibility 1
    • create a function that accepts an array and an item to find in that array
    • create a variable for a counter
    • flatten the array
    • loop through the array
      • every time the item is found in that array increment the counter
    • return the counter at the end
  • possibility 2
    • create a function that accepts an array and an item to find in that array
    • flatten the array
    • filter the array by the item that was passed in
    • get the length of that array

Solution 1

First we need to create a function that accepts an array and an item

const itemCounter = (array, item) => {
    //create a variable for a counter
    //flatten the array
    //loop through the array
    //every time the item is found in that array increment the counter
    //return the counter at the end
}
Enter fullscreen mode Exit fullscreen mode

Create a variable that will hold a counter

const itemCounter = (array, item) => {
    let counter = 0
    //flatten the array
    //loop through the array
    //every time the item is found in that array increment the counter 
    //return the counter at the end
}
Enter fullscreen mode Exit fullscreen mode

We need to flatten the array and since we don’t know how many nested arrays there are we are going to pass .flat() Infinity. .flat() will flatten an array the same number of times you pass to it. Since we don’t know how many times this will be we will pass Infinity, which will flatten the array until it is completely flat.

const itemCounter = (array, item) => {
    let counter = 0
    array.flat(Infinity)
    //loop through the array
    //every time the item is found in that array increment the counter
    //return the counter at the end
}
Enter fullscreen mode Exit fullscreen mode

We want to loop through the flattened array so I am going to chain a .forEach on the .flat(). This is a lot like a for loop just a different syntax. To read more about it check out this MDN page.

const itemCounter = (array, item) => {
    let counter = 0
    array.flat(Infinity).forEach(x => {
    })
    //every time the item is found in that array increment the counter 
}
Enter fullscreen mode Exit fullscreen mode

If the item that we are currently on in the forEach loop matches the item that is passed we want to increment the counter. If not we want to continue the loop.

const itemCounter = (array, item) => {
  let counter = 0
  array.flat(Infinity).forEach(x => {
    if(x == item){ counter++ }
  });
  //return counter
}
Enter fullscreen mode Exit fullscreen mode

Last but not least we need to return the counter.

const itemCounter = (array, item) => {
  let counter = 0
  array.flat(Infinity).forEach(x => {
    if(x == item){ counter++ }
  });
  return counter
}
Enter fullscreen mode Exit fullscreen mode

Solution 2

First we need to create a function that accepts an array and an item and flatten the array. This will be the same as the previous solution.

const itemCounter = (array, item) => {
  array.flat(Infinity)
  //filter the array by the item that was passed in
  //get the length of that array
}
Enter fullscreen mode Exit fullscreen mode

To filter the array we are going to use .filter(). If you are unfamiliar with it you can check out this MDN page but it creates a new array of the elements that meet the criteria in the function that you pass it.

const itemCounter = (array, item) => {
  array.flat(Infinity).filter(currentItem => currentItem === item)
  //get the length of that array
}
Enter fullscreen mode Exit fullscreen mode

Now we just have to get the length. I am also going to clean it up a bit and we get this.

const itemCounter = (array, item) => array.flat(Infinity).filter(currentItem => currentItem == item).length;
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this case the performance for each is the same. I like the second solution because its substantially less code and its still easy to read but both solutions are good. Below are my jsbench results for those who are curious.
Alt Text
I hope you had fun with this one! Please leave your solutions that you came up with in the comments section. If you have any challenge you would like to see done also leave that in the comments below you may see it come up! If you would like to get the challenge emailed to you every day in morning and a notification when the solution is posted subscribe here.

Discussion (3)

pic
Editor guide
Collapse
t0nyba11 profile image
Tony B

I was curious how fast this could go.
This seems to run 33% quicker than your solutions.
JavaScript still needs hand holding it seems. :)

const itemCounter = (array, item) =>
{
let count = 0;
const stack = [array];
while(stack.length > 0)
{
const x = stack.pop();
if(Array.isArray(x))
stack.push(...x)
else
count += (x === item);
}

return count;
}

Collapse
hellodevworldblog profile image
Hello Dev World Blog Author

I’m surprised that run 33% faster as it’s very similar to the first solution but it’s also possible that the .flat function isn’t super performant (wouldn’t surprise me) I’ll have to check that out tomorrow!

Collapse
hellodevworldblog profile image
Hello Dev World Blog Author

Interesting stack overflow comment on it stackoverflow.com/questions/614117...

If you were interested :)

The one below it is also interesting