是否可以在Javascript中对嵌套数组使用闭包和递归方法



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

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";这是最深的子数组,所以很明显我的函数没有升级,我缺少了一些东西。

我怎样才能做到这一点?

提前谢谢。

如果您只更改,您的功能就可以正常工作

return foo(arr[i]);

收件人:

foo(arr[i]);

您需要让整个循环运行(显然),返回会使它提前停止。

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

您不需要嵌套函数,您可以声明一个递归函数,并且仍然保持所有内容都是自包含的。

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)使用curried闭包进行前面的递归

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

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

这听起来像是学习递归的练习。如果是这样的话,我就让你看看这里的其他精细递归答案。

但一个简单的替代方案是注意数组的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))

递归是一种函数继承,因此将其与函数样式一起使用会产生最佳结果。这意味着要避免突变、变量重新分配和其他副作用。这里有一种方法,我们可以使用类型分析和归纳推理重写程序

string

  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

最新更新