【问题标题】:Is it possible to use closure and recursive approach for nested arrays in Javascript是否可以在Javascript中对嵌套数组使用闭包和递归方法
【发布时间】:2021-12-04 00:09:15
【问题描述】:

我需要计算嵌套数组中的元音,我想用闭包来避免全局命名空间污染。 这是我的代码:

let nestedArr = [
    "Elie",
    ["Matt", ["Tim"]],
    ["Colt", ["Whiskey", ["Janey"], "Tom"]],
    "Lorien"
];


function countVowels() {
    let vowelsCount = 0;
    let vowels = ['a', 'e', 'i', 'o', 'u'];
    return function foo(arr) {
        for (let i = 0; i < arr.length; i++) {
            if (typeof arr[i] === 'string') {
                for (let letter of arr[i]) {
                    if (vowels.includes(letter.toLowerCase())) {
                        vowelsCount++;
                    }
                }
            } else {
                return foo(arr[i]);
            }
        }
        return vowelsCount;
    }
}

const counter = countVowels();
console.log(counter(nestedArr));

我希望元音的数量正确,但得到 5 个。我尝试调试并看到它在最深的子数组“Tim”之后停止,所以显然我的函数没有升级,我错过了一些东西。

我怎样才能做到这一点?

提前谢谢你。

【问题讨论】:

    标签: javascript recursion multidimensional-array closures


    【解决方案1】:

    只要你改变,你的功能就可以正常工作

    return foo(arr[i]);
    

    收件人:

    foo(arr[i]);
    

    你需要让整个循环运行(显然),return 使它更早停止。

    let nestedArr = [
        "Elie",
        ["Matt", ["Tim"]],
        ["Colt", ["Whiskey", ["Janey"], "Tom"]],
        "Lorien"
    ];
    
    
    function countVowels() {
        let vowelsCount = 0;
        let vowels = ['a', 'e', 'i', 'o', 'u'];
        return function foo(arr) {
            for (let i = 0; i < arr.length; i++) {
                if (typeof arr[i] === 'string') {
                    for (let letter of arr[i]) {
                        if (vowels.includes(letter.toLowerCase())) {
                            vowelsCount++;
                        }
                    }
                } else {
                   foo(arr[i]);
                }
            }
            return vowelsCount;
        }
    }
    
    const counter = countVowels();
    console.log(counter(nestedArr));

    【讨论】:

      【解决方案2】:

      你不需要嵌套函数,你可以声明一个递归函数,并且仍然保持一切自包含。

      const countVowels = (arr) => {
        const vowels = ['a', 'e', 'i', 'o', 'u'];
        const vowel_count = (s) => [...s].filter((c) => vowels.includes(c.toLowerCase())).length;
      
        let vowels_total = 0;
      
        for (const e of arr) {
          vowels_total += Array.isArray(e) ? countVowels(e) : vowel_count(e);
        }
      
        return vowels_total;
      };
      
      const nestedArr = ['Elie', ['Matt', ['Tim']], ['Colt', ['Whiskey', ['Janey'], 'Tom']], 'Lorien'];
      
      console.log(countVowels(nestedArr));

      或者,使用Array#flat()(到Infinity)使用咖喱闭包进行递归

      const countVowels = (
        (v) => (arr) =>
          [...arr.flat(Infinity).join('')].filter((c) => v.includes(c.toLowerCase())).length
      )(['a', 'e', 'i', 'o', 'u']);
      
      const nestedArr = ['Elie', ['Matt', ['Tim']], ['Colt', ['Whiskey', ['Janey'], 'Tom']], 'Lorien'];
      
      console.log(countVowels(nestedArr));

      【讨论】:

        【解决方案3】:

        let nestedArr = [
          'Elie',
          ['Matt', ['Tim']],
          ['Colt', ['Whiskey', ['Janey'], 'Tom']],
          'Lorien',
        ];
        
        function countVowels(str) {
          return str.match(/['a', 'e', 'i', 'o', 'u']/gi)?.length || 0;
        }
        
        function vowelsAmount(arr) {
          return arr.reduce((accumulator, currentElement) => {
            return Array.isArray(currentElement)
              ? (accumulator += vowelsAmount(currentElement))
              : (accumulator += countVowels(currentElement));
          }, 0);
        }
        
        console.log(vowelsAmount(nestedArr));

        【讨论】:

        【解决方案4】:

        这听起来像是一个学习递归的练习。如果是这样,我让你在这里找到其他好的递归答案。

        但一个简单的替代方法是注意数组的toString 格式,并意识到我们可以简单地将测试应用于结果,留下一些非常简单的代码:

        const countVowels = (a) =>
          [... a .toString () .toLowerCase ()] .filter (c => 'aeiou' .includes (c)) .length
        
        const nestedArr = ['Elie', ['Matt', ['Tim']], ['Colt', ['Whiskey', ['Janey'], 'Tom']], 'Lorien']
        
        console .log (countVowels (nestedArr))

        【讨论】:

          【解决方案5】:

          递归是一种函数式遗产,因此将其与函数式风格一起使用会产生最佳效果。这意味着避免诸如突变、变量重新分配和其他副作用之类的事情。这是我们可以使用类型分析和inductive reasoning

          重写程序的一种方法

          字符串

          1. 如果输入t 少于一个字符,则没有什么可计算的。返回空总和,0。
          2. (归纳)t 至少有 1 个字符。如果第一个字符是元音,则将其转换为 1,否则为 0,并将其添加到子问题的结果中。

          数组

          1. 如果输入t 的元素少于一个,则没有可计数的元素。返回空总和,0
          2. (感应)t 至少有一个元素。计算第一个元素的元音并将其添加到子问题的结果中。

          任何其他类型

          • 如果输入 t 既不是字符串也不是数组,则抛出错误以通知调用者我们无法计算该输入类型的元音。

          function countVowels (t) {
            switch (t?.constructor) {
              case String:
                if (t.length < 1)
                  return 0                                             // 1
                else
                  return isVowel(t[0]) + countVowels(t.slice(1))       // 2
              case Array:
                if (t.length < 1)
                  return 0                                             // 1
                else
                  return countVowels(t[0]) + countVowels(t.slice(1))   // 2
              default:
                throw Error(`cannot count input type: {t?.constructor}`)
            }
          }
          
          function isVowel (t) {
            switch (t.toLowerCase()) {
              case "a":
              case "e":
              case "i":
              case "o":
              case "u":
                return true
              default:
                return false
            }
          }
          
          const nestedArr =
            ['Elie', ['Matt', ['Tim']], ['Colt', ['Whiskey', ['Janey'], 'Tom']], 'Lorien']
          
          console.log(countVowels(nestedArr))
          14
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-08-15
            • 2014-02-20
            • 1970-01-01
            • 2018-02-04
            • 2016-07-06
            • 2019-10-12
            • 1970-01-01
            • 2018-04-20
            相关资源
            最近更新 更多