【问题标题】:Recursively loop through an array and return number of items?递归循环遍历数组并返回项目数?
【发布时间】:2016-06-22 19:51:12
【问题描述】:

如果以前有人问过这个问题,但我找不到答案,我深表歉意。如何循环遍历具有嵌套数组的数组并在控制台中打印出项目出现的实例数?

所以console.log 应该打印出名称“bob”的数字 2,因为“bob”在数组中出现了两次。

这是我的数组以及我目前拥有的:

    var names = ["bob", ["steve", "michael", "bob", "chris"]];

    function loop(arr, item) {
      for (var i = 0; i < arr.length; i++) {
        if (arr[i] instanceof Array) {
          loop(arr[i], item);
        } else {
          if (arr[i] == item) {
            console.log(arr[i]);
          }
        }
      }
    }

    loop(names, "bob");

【问题讨论】:

标签: javascript arrays recursion


【解决方案1】:

在这里,请注意,您可以在内部保留计数器值,以保持代码的其余部分更简洁:

var names = ["bob", ["steve", "michael", "bob", "chris"]];

function loop(arr, item) {
  var result = 0;
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] instanceof Array) {
      result += loop(arr[i], item);
    } else {
      if (arr[i] == item) {
        result++;
      }
    }
  }
  return result;    
}


var result = loop(names, "bob");
console.log(result);

【讨论】:

    【解决方案2】:

    你需要一个柜台

    function loop(arr, item) {
        var count = 0;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] instanceof Array) {
                count += loop(arr[i], item);
            } else {
                if (arr[i] == item) {
                    count++;
                    console.log(arr[i]);
                }
            }
        }
        return count;
    }
    
    var names = ["bob", ["steve", "michael", "bob", "chris"]],
        count = loop(names, "bob");
    
    document.write(count);

    【讨论】:

      【解决方案3】:

      你也可以使用reduce

      var names = ['bob', ['steve', 'michael', 'bob', 'chris', ['bob']]];
      
      function count(item, items) {
        return items.reduce(function(sum, x) {
          if (Array.isArray(x)) return sum + count(item, x);
          if (x === item) return sum + 1;
          return sum;
        }, 0);
      }
      
      count('bob', names); // => 3
      

      另一种选择是使用更通用的函数并将它们链接在一起。

      1. 展平输入数组; [1,[2,3,4,5,[6]]] => [1,2,3,4,5,6]
      2. 过滤每个元素与您的搜索元素匹配的扁平数组
      3. 返回过滤后数组的长度

      看起来像这样

      flatten(names).filter(x => x === 'bob').length
      

      我将把 flatten 的实现留给你做练习

      【讨论】:

        【解决方案4】:

        一种纯粹的递归形式,不需要外部变量。

        尝试如下修改你的逻辑,

        罢工>

        var names = ["bob", ["steve", "michael", "bob", "chris",["bob"]]];
        function loop(arr, item, cnt){
           cnt = cnt || 0;
           for(var i = 0; i < arr.length; i++){
             if(arr[i]==item){ cnt++; }
             else if(arr[i] instanceof Array) { return loop(arr[i], item, cnt); } 
           }
           return cnt;
        }
        
        loop(names,"bob"); //3
        

        var names = ["bob", ["steve", "michael", "bob", "chris", ["bob"],["bob",["bob"]]], "bob"];
        
        function find(arr, txt, cnt, match) {
          cnt = cnt || 0;
          match = match || 0;
          if (arr[cnt] === txt) { match++; } 
          else if (arr[cnt].push) { match = find(arr[cnt], txt, 0, match); } 
          if (++cnt === arr.length) { return match; }
          return find(arr, txt, cnt, match);
        }
        
        alert(find(names, "michael")); //6
        

        【讨论】:

        • 不需要引入另一个参数。
        • 这是一个改进,尽管我会接受其他答案,因为它们不依赖于向下递归传播另一个对象,而是向上传播结果。
        • @Aldehir 这是他们的方法,这是我的。没有必要坚持更多的受众。这不会对性能产生任何影响。
        • 这在*数组中稍后存在另一个匹配项的情况下不起作用,例如["bob", ["steve", "michael", "bob", "chris",["bob"]], "bob"],因为它返回得太早。将 return loop(arr[i], item, cnt); 更改为 cnt = loop(arr[i], item, cnt); 将解决此问题。
        【解决方案5】:

        const names = ["bob", ["steve", "michael", "bob", "chris"]];
        
        function loop(arr, item) {
            let res = 0;
        
            for (let v of arr) {
                if (typeof v === 'object') res += loop(v, item);
                if (v === item) res++;
            }
        
            return res;    
        }
        
        
        
        const result = loop(names, "bob");
        console.log(result);

        【讨论】:

          【解决方案6】:

          截至 2020 年,我们拥有 Array.prototype.flat 方法,这使这项任务变得微不足道。

          给你。

          const names = ["bob", ["steve", "michael", "bob", "chris"]];
          const nestedNames = ["bob", ["steve", ["michael", ["bob", ["chris"]]]]];
          
          function countName(array, name, depth = Infinity) {
            return array.flat(depth).reduce((acc, cur) => acc + (cur === name ? 1 : 0), 0);
          }
          
          console.log(countName(names, 'bob')); // 2
          console.log(countName(names, 'chris')); // 1
          
          console.log(countName(nestedNames, 'bob')); // 2
          console.log(countName(nestedNames, 'chris')); // 1

          【讨论】: