用递归展平数组

时间:2019-08-11 01:03:19

标签: javascript 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有时求值为{{1} }。

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

4 个答案:

答案 0 :(得分:0)

我不知道是否可以在这里回答我自己的问题,但是我找到了答案,并且我不想让这个问题没有答案。

  

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

     

我想了解为什么会发生这种情况,我认为直接假设temp总是等于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));

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

答案 1 :(得分:0)

尝试以下代码,这只是对答案的修改。

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

请参阅代码中的注释,以了解进行这些更改的原因。

// 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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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