因此,这是一个解决扁平化阵列问题的示例解决方案。我的问题不是'如何'平整阵列。相反,我试图理解在这个递归中发生的一些基本功能。
此解决方案遍历原始数组的每个元素,通过将它们放回函数中来分解任何数组元素,直到它们不再是数组并且可以推送到新数组。
我的问题是,' for'循环跟踪元素通过函数返回的所有时间,并继续循环遍历原始'的其余部分。它当时正在处理的数组?它必须以某种方式保持跟踪,否则每次元素是一个数组并被放回时,当前循环将被缩短。希望我的问题有道理。
function steamrollArray(array) {
var flatArray = [];
flatten(array);
function flatten(array) {
for (var i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
flatten(array[i]);
} else {
flatArray.push(array[i]);
}
}
}
return flatArray;
}
steamrollArray([1, [2], [3, [[4]]]]);
答案 0 :(得分:3)
我认为会有更好的答案,但这里有......
至少,不要把它想象成&#34;打破&#34;循环,将其视为继续按程序顺序执行代码。因此,从循环的上下文中,它将自身称为函数,当该函数完成时,它将继续循环。实施例
var item = [1, [2, 3], 4]
flatten(item)
的执行将是:
Loop 1:
Push 1
Loop 2:
Start a call to flatten with [2, 3]
Loop 1:
push 2
Loop 2:
push 3
End loop
Loop 3:
Push 4
End Loop.
所以重点是,它只是执行一个步骤。它不需要记住&#34;它是什么时候,当一个函数返回时,javascript只是继续从调用函数的地方开始处理。
您可以查看call stacks。
答案 1 :(得分:2)
结果数组flatArray
位于辅助函数的词法闭包中,因此不是自身数组的元素被推送到此,并且它们在结果上的顺序按它们的顺序排列迭代。
当其中一个元素是一个数组时,它调用flatten(array[i])
,在返回之前展平该元素的元素。与所有函数一样,语句的执行需要在完成下一个语句之前完成,并且调用函数根本不会取消当前函数。它会恢复并持续到结束或return
语句。
想象一下这个功能:
function test () {
console.log("hello, ");
console.log("world!");
}
当调用它时,它会等到整个console.log("hello, ")
完成后再执行语句二(console.log("world!")
)。如果它是递归调用,那么调用需要在执行语句二之前完成。它对所有函数调用都是一样的,不仅仅是递归调用。
答案 2 :(得分:1)
它实际上并没有把元素放回去&#39;通过只发生一次的功能。它检查一个元素是否是一个数组,然后遍历该数组。
如果它不是数组,则将其推送到flatArray
。这里的递归是,如果任何元素是一个数组,它将通过flatten函数。然后,如果该数组的元素是一个数组,那么元素将被发送到flatten等等等等。
让我们看一下以下示例:[1, [2], [3, [[4]]]]
我们开始循环 - &gt;
答案 3 :(得分:1)
跟踪&#39;每个递归步骤的发生方式与任何其他方法调用的工作方式相同;只要在call stack中调用新方法,javascript引擎就会跟踪变量和范围。
对于您的具体示例,当<p id="id1"></p>
<p id="id2"></p>
函数不再嵌套时,可能会更容易看到发生了什么。
flatten
由于function steamrollArray(array) {
var flatArray = [];
flatten(array, flatArray);
return flatArray;
}
function flatten(array, flatArray) {
flatArray = flatArray || [];
for (var i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
flatten(array[i]);
} else {
flatArray.push(array[i]);
}
}
}
steamrollArray([1, [2], [3, [[4]]]]); # [1, 2, 3, 4]
函数无法再访问flatArray
变量,因此需要进行一些细微的修改。但是这些mod使得flatten
似乎是多余的......让我们摆脱它。
steamrollArray
现在,递归发生的地点和方式更加明显。任何时候发现一个数组&#39;它也会被展平。值可以推送到新数组,也可以推送到作为第二个参数传递的数组中。每次function flatten(array, flatArray) {
flatArray = flatArray || [];
for (var i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
flatten(array[i], flatArray);
} else {
flatArray.push(array[i]);
}
}
return flatArray;
}
flatten([1, [2], [3, [[4]]]]); # [1, 2, 3, 4]
循环内调用flatten
时,for
位置的数组本身都会展平并推送到i
。由于flatArray
也以递归方式传递给flatArray
函数,所有值都将被收集到该数组中。
答案 4 :(得分:0)
我有一个更简单的解决方案,适用于任何级别的数组嵌套。
function flattenArray(arr){
for(var i=0;i<arr.length;i++){
if(arr[i] instanceof Array){
Array.prototype.splice.apply(arr,[i,1].concat(arr[i]))
i--;
}
}
return arr;
}
答案 5 :(得分:0)
使用for-of
循环和另外两种方法来展平数组的解决方案
使用for-of循环
let array = [1, [2], [3, [[4]]]];
let output = [];
let flattenArray = (arr) => {
for(let a of arr) {
Array.isArray(a) ? flattenArray(a) : output.push(a);
}
return output;
}
console.log(flattenArray(array));
使用reduce()
方法
let array = [1, [2], [3, [[4]]]]
function flattenArray(ary) {
return ary.reduce((acc, val) => {
if (Array.isArray(val)) {
return acc.concat(flattenArray(val))
}
return acc.concat(val)
},[])
}
console.log(flattenArray(array));
使用flat()
方法
let array = [1, [2], [3, [[4]]]];
let output = array.flat(Infinity); // use Infinity for flattening nested levels.
console.log(output);