繁体   English   中英

用递归展平数组

[英]flattening an array with recursion

到目前为止,递归一直是我的难题。 作为一项任务,我尝试使用递归从头开始编写代码。 我写了这个函数来展平数组。

 function foo(item) { if (item instanceof Array) { for (let ii of item) { foo(ii); } } else { let bar = item; console.log(bar); return bar; } } function arrFlatten(arr) { let result = []; for (let i of arr) { let temp = foo(i); console.log(temp); result.push(temp); } console.log(result); return result; } let bar = [1, [2], [3, [[4]]]]; arrFlatten(bar); 

我放了2 console.log()一个正在打印变量bar ,另一个正在打印变量temp

通过运行代码可以看到,在else块中, bar求值正确,但是当我返回它时,变量temp有时有时求值为undefined

我想了解为什么会发生这种情况,我认为直接假设temp总是等于bar

我不知道是否可以在这里回答我自己的问题,但是我找到了答案,我也不想离开这个问题。

通过运行代码可以看到,在else块内,bar的求值正确,但是当我返回它时,变量temp有时立即求值为undefined。

我想了解为什么会这样,我认为假设温度始终等于bar是很直接的。

temp有时返回undefined的原因是因为没有考虑到所有javascript函数都返回undefined除非另有说明。

那些undefined的事正在发生

function foo(item) {
  if (item instanceof Array) {
    for (let ii of item) {
      foo(ii);
    }
  } else {
    let bar = item;
    console.log(bar);
    return bar;
  }
}

每次for loop结束且函数结束时,函数将返回undefined

知道这一点,我不得不像这样重写代码。

function foo(item, arr=[]) {
  let result;
  if (item instanceof Array) {
    for (let ii of item) {
      result = foo(ii, arr);
    }
  } else {
    arr.push(item);
    return arr;
  }
  return result;
}


let bar = [1, [2], [3, [[4, 5], 6], 7], 8];
console.log(foo(bar));

这不是最优雅的方法,但是可以完成工作。

试试下面的代码,它只是对答案的修改。

我认为这将是更好的方法,并且您会更清楚地了解它。

请参阅代码中的注释,以了解我为什么进行这些更改。

// You don't need a 2nd argument, so remove it
function flatten(items){
       let result = [];

       // for loop should be outside the if statement 
       for(let item of items){
             if(item instanceof Array){
                    // flatten recursively, returned array will contain flattened subarray
                    var flattenedItems = flatten(item);
                    for(let flattenedItem of flattenedItems){
                           // Since flattenedItems are returned by 
                        // a recursive call to this function itself,
                          // it is guaranteed that all the elements of 
                          // flattenedItems will already flatted
                        // So, its safe to directly push it to result
                          result.push(flattenedItem);
                   }
             }
             else{
                     result.push(item);
                     // do not return here as I moved for loop out of the if statement
            }
       }
       return result;
}

console.log(flatten([1, [2], [3, [[4, 5], 6], 7], 8]));

// 1, 2, 3, 4, 5, 6, 7, 8

您可以利用某些语言构造或本机方法取消嵌套数组:

const a = [[1,2],[3,4]];

使用价差运算符:

[...a[0], ...a[1]];
//=> [1,2,3,4]

使用concat

[].concat(a[0], a[1]);
//=> [1,2,3,4]

使用flatMap

a.flatMap(x => x);
//=> [1,2,3,4]

您可以在递归函数中将相同的原理应用于任何深度的嵌套数组:

注意:IE / Edge不支持flatMap

 const flatten = arr => arr.flatMap(x => Array.isArray(x) ? flatten(x) : x); console.log(flatten([1, [2], [3, [[4]]]])); console.log(flatten([1, [2], [3, [[4, 5], 6], 7], 8])); 

undefined打印到控制台的原因是,并非foo函数的所有分支都具有返回值。 如果命中if语句,它将返回undefined (因为未指定返回值)。

您可以使用Array.prototype.flat简化您的功能(请记住,它的支持有限)。 flat不会无限地变平坦。 但是,文档中提到了Alternatives ,从中可以递归地变平。

 //to enable deep level flatten use recursion with reduce and concat var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]]; function flattenDeep(arr1) { return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []); } flattenDeep(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4] 

 function flattenDeep(arr) { return arr.reduce( (acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), [] ); } const bar = [1, [2], [3, [[4]]]]; console.log(flattenDeep(bar)); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM