给定一个像这样的多维数组:
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
}
我想如果你继续返回计数值并在计算中使用它,你将能够得到一个没有外部变量的最终数字:
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并获取递归调用的结果并将它们添加到本地总计。
尼娜的答案更优雅,但也许这将更容易理解。
您可以对数组采用递归方法或检查值并添加布尔值的结果。
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'));
我认为这是一个简单的方法,但你可以纠结于它:
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)))
你可以使用arr.toString().split(",")
迭代arr的平面版本,这样你就不需要递归了。
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(",")
一起使用