是否可以对 Javascript 中的嵌套数组使用闭包和递归方法
Is it possible to use closure and recursive approach for nested arrays in 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”之后停止,所以很明显我的函数没有升级,我遗漏了一些东西。
我怎样才能做到这一点?
提前谢谢你。
您不需要嵌套函数,您可以声明一个递归函数并仍然保持所有内容独立。
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));
如果你只是改变你的功能就可以正常工作
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));
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))
递归是一种函数式继承,因此将它与函数式风格一起使用会产生最佳效果。这意味着要避免诸如突变、变量重新分配和其他副作用之类的事情。这是我们可以使用类型分析和 inductive reasoning
重写程序的一种方法
字符串
- 如果输入的
t
少于一个字符,则不算数。 Return 空和,0.
- (归纳法)
t
至少有 1 个字符。如果第一个字符是元音,则将其转换为 1,否则转换为 0,并将其添加到子问题的结果中。
数组
- 如果输入
t
的元素少于1个,则没有什么可统计的。 Return空和,0
- (inductive)
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
我需要计算嵌套数组中的元音,我想用闭包来完成它以避免全局命名空间污染。 这是我的代码:
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”之后停止,所以很明显我的函数没有升级,我遗漏了一些东西。
我怎样才能做到这一点?
提前谢谢你。
您不需要嵌套函数,您可以声明一个递归函数并仍然保持所有内容独立。
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));
如果你只是改变你的功能就可以正常工作
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));
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))
递归是一种函数式继承,因此将它与函数式风格一起使用会产生最佳效果。这意味着要避免诸如突变、变量重新分配和其他副作用之类的事情。这是我们可以使用类型分析和 inductive reasoning
重写程序的一种方法字符串
- 如果输入的
t
少于一个字符,则不算数。 Return 空和,0. - (归纳法)
t
至少有 1 个字符。如果第一个字符是元音,则将其转换为 1,否则转换为 0,并将其添加到子问题的结果中。
数组
- 如果输入
t
的元素少于1个,则没有什么可统计的。 Return空和,0 - (inductive)
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