counting how many times an item appears in a multidimensional array in javascript

送分小仙女□ 提交于 2021-02-17 02:03:11

问题


Given a multidimensional array like this:

 var arr = [
"apple",
["banana", "strawberry","dsffsd", "apple"],
"banana",
["sdfdsf","apple",["apple",["nonapple", "apple",["apple"]]]]
,"apple"];

the challenge was to write a function that keeps the array and an item as arguments and return how many times that item appears in the array.

My first solution did the trick:

function countItems(arr, item, sumarr = []) { // sumarr = array to store items matched

for (let i = 0; i < arr.length; i++ ){ // iterate on arr

    let isarray = arr[i].constructor === Array // if the element is a nested array

    if(isarray){  countItems(arr[i], item, sumarr) } // recursion

    let isin = arr[i] === item; // ELSE if the item is in the arr
    if(isin) { sumarr.push(arr[i])}; // add the element in the summ array



}
console.log(sumarr); // I preferred an array over a simple counter to be able to double check the result
return sumarr.length; // the length of the sum array show how many items founded
}

The problem is that if I try to use a counter (a variable to increment) instead of an array to store the values, I have a wrong result (instead of 7 in this case console.log(countItems(arr, "apple")); I have 2). If I get it right it's because of the recursion function that brings closure, because if I use a global variable it works.

How achieve that without a global variable?

With the global variable it's like that:

    let totc = 0;

function countItems(arr, item) { 


    for (let i = 0; i < arr.length; i++ ){ // iterate on arr
        let isarray = arr[i].constructor === Array; // if the element is a nested array
        if(isarray){  countItems(arr[i], item) } // recursion

        let isin = arr[i] === item; // ELSE if the item is in the arr
        if(isin) { totc ++;  };



    }
    return totc; // the length of the sum array show how many items founded
  }

回答1:


i think if you continue to return the count value and use it in your calculation you will be able to to get a final number without an outside variable:

function countItems(arr, item) {
  let totc = 0; // totc is now local
  for (let i = 0; i < arr.length; i++ ){ // iterate on arr
        let isarray = arr[i].constructor === Array; // if the element is a nested array
        if(isarray){  totc += countItems(arr[i], item) } // recursion, using the return value



        let isin = arr[i] === item; // ELSE if the item is in the arr
        if(isin) { totc ++;  };



    }
    return totc; // the length of the sum array show how many items founded
  }
}

note that the only changes i made were to instantiate totc inside the function and to take the result of recursive calls and add them to the local total.

Nina's answer is more elegant, but perhaps this will be easier to understand.




回答2:


You could take a recursive approach for arrays or check the value and add the result of the boolean value.

function count(array, value) {
    return array.reduce((s, a) => s + (Array.isArray(a) ? count(a, value) : a === value), 0);
}

var array = ["apple", ["banana", "strawberry", "dsffsd", "apple"], "banana", ["sdfdsf", "apple", ["apple", ["nonapple", "apple", ["apple"]]]], "apple"];

console.log(count(array, 'apple'));

Version with a for loop.

function count(array, value) {
    var i,
        sum = 0;

    for (i = 0; i < array.length; i++) {
        if (Array.isArray(array[i])) {
            sum += count(array[i], value);
            continue;
        }
        sum += array[i] === value;
    }
    return sum;
}

var array = ["apple", ["banana", "strawberry", "dsffsd", "apple"], "banana", ["sdfdsf", "apple", ["apple", ["nonapple", "apple", ["apple"]]]], "apple"];

console.log(count(array, 'apple'));



回答3:


I think this is a simple approach but you can get tangled with it:

 function countItems(arr, item, count = 0){
     if(!arr.length) return count; //if the array is empty then there's nothing else to count
     let cTemp;
     if(Array.isArray(arr[0])){ //if the next item is an array
         cTemp = countItems(arr[0], item); //count the items in that array
     } else {
         cTemp = arr[0] === item ? 1 : 0; //if it's a string the compare it with item
         //1 if we found it
         //0 if we didn't
     }
     return countItems(arr.slice(1), item, count+cTemp);
     //count the items of the rest of the array and add what we found
     //arr.slice(1) is the rest of the array
     //cTemp is the count for the first item in the array
 }

Which of course can be rewritten into a single line:

 let countItems = ([first, ...rest], item, count = 0) => !first ? count : countItems(rest, item, count + (Array.isArray(first) ? countItems(first, item) : +(first === item)))



回答4:


You could iterate the flat version of arr using arr.toString().split(",") so you don't need recursion.

var arr =  [
    "apple",
    ["banana", "strawberry","dsffsd", "apple"],
    "banana",
    ["sdfdsf","apple",["apple",["nonapple", "apple",["apple"]]]]
    ,"apple"];


var counts = {};


 arr.toString().split(",").forEach(e=>{
    counts[e] = (counts[e] || 0) +1
 })   

 console.log(counts.apple)

Doesn't work if elements have "," inside, but works with.flat() instead of .toString().split(",")



来源:https://stackoverflow.com/questions/52084228/counting-how-many-times-an-item-appears-in-a-multidimensional-array-in-javascrip

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!