считая, сколько раз элемент появляется в многомерном массиве в JavaScript - PullRequest
0 голосов
/ 29 августа 2018

Учитывая многомерный массив, подобный этому:

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

Задача состояла в том, чтобы написать функцию, которая хранит массив и элемент в качестве аргументов и возвращает количество раз, когда этот элемент появляется в массиве.

Мое первое решение помогло:

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
}

Проблема в том, что если я пытаюсь использовать счетчик (переменную для приращения) вместо массива для хранения значений, у меня будет неправильный результат (вместо 7 в данном случае console.log(countItems(arr, "apple")); у меня 2). Если я правильно понял, это из-за функции рекурсии, которая вызывает замыкание, потому что, если я использую глобальную переменную, она работает.

Как этого добиться без глобальной переменной?

С глобальной переменной это так:

    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
  }

Ответы [ 4 ]

0 голосов
/ 29 августа 2018

Я думаю, что это простой подход, но вы можете запутаться с ним:

 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
 }

Что, конечно, можно переписать в одну строку:

 let countItems = ([first, ...rest], item, count = 0) => !first ? count : countItems(rest, item, count + (Array.isArray(first) ? countItems(first, item) : +(first === item)))
0 голосов
/ 29 августа 2018

Вы можете выполнить итерацию плоской версии arr, используя arr.toString().split(","), чтобы вам не требовалась рекурсия.

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)

Не работает, если элементы имеют "," внутри, но работает с. flat () вместо .toString().split(",")

0 голосов
/ 29 августа 2018

Я думаю, что если вы продолжите возвращать значение счетчика и использовать его в своих вычислениях, вы сможете получить окончательное число без внешней переменной:

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
  }
}

обратите внимание, что единственными изменениями, которые я сделал, было создание экземпляра totc внутри функции, получение результата рекурсивных вызовов и добавление их к локальному итогу.

Ответ Нины более элегантный, но, возможно, это будет легче понять.

0 голосов
/ 29 августа 2018

Вы можете использовать рекурсивный подход для массивов или проверить значение и добавить результат логического значения.

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'));

Версия с петлей for.

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'));
...