使用递归展平嵌套数组(不使用循环)

Flatten nested arrays using recursion (and without using loops)

我的问题逻辑,使用以下内容作为输入。

var input = [['A','B'],1,2,3,['C','D']]
  1. 使用 Array.isArray(input)
  2. 检查第一个元素是否为数组
  3. 如果第一个元素是数组,调用函数,第一个元素 ['A,'B'] 作为参数。
  4. 嵌套数组的第一个元素是'A',它不是一个数组,因此将这个元素压入结果数组,并将这个元素移出。重复函数调用。

尝试使用递归展平嵌套数组时,函数的输入变量不断被重新分配,阻止我使用原始数组再次调用函数。如何防止重新分配原始输入变量?

我知道这不是完整的解决方案,但是当我将第一个元素移出嵌套数组时,我卡住了。

我已经一步一步地完成了这个功能,但肯定有一些我遗漏的东西,另一双眼睛会很有帮助。

我也一直在使用我的chrome开发者工具,设置断点来一步步监控函数。

//Defining original input variable
var input = [['A','B'],1,2,3,['C','D']]

function flat(array){
    var result = []
    var firstElement = array[0]

//CHECK IF FIRST ELEMENT IS ARRAY OR NOT
    if(Array.isArray(firstElement)){
    return flat(firstElement)  
    } 


//IF ELEMENT NOT ARRAY, PUSH ELEMENT TO RESULT
    else{result.push(firstElement)
    array.shift() //removing child element
    return (flat(array)) //call function on same array
    }

if(array.length===0){return result}

}

第一次迭代: firstElement = ['A','B'], Array.isArray(firstElement) 为真,因此调用 flat(firstElement)

第二次迭代: firstElement = 'A', Array.isArray(firstElement) 为假,所以我们 1. 向下跳将这个元素压入result 2. 使用 array.shift() 删除 'A' 3. 调用 flat(array),其中 array 现在是 ['B']

第三次迭代: firstElement = 'B', Array.isArray(firstElement) 为假 1. 跳下来把这个元素压入result,result现在只有['B'],因为我调用函数的时候重置了result。 2. 使用 array.shift() 删除 'B',数组现在为空,->[ ] 3. 我如何跳出并在原始输入数组上使用 flat()?

如果您想避免循环,我正在考虑将 concating/spreading 数组作为循环,您需要将结果数组传递给您的函数。

const input = [['A', 'B'], 1, 2, 3, ['C', 'D']]

// Start the function with an empty result array.
function flat(array, result = []) {
  if (!array.length)
    return result

  // Extract first element.
  const first = array.shift()

  // Call the function with the array element and result array.
  if (Array.isArray(first))
    flat(first, result)
  // Or add the non array element.
  else
    result.push(first)

  // Call the function with the rest of the array and result array.
  flat(array, result)
  return result

}

console.log(flat(input))

如果第一个元素是数组,您的代码不会考虑以下元素。下面的解决方案使用 array.concat(...) 来组合递归的结果(沿着树向下),但也组合处理列表其余部分的结果(在同一级别)。将问题可视化为一棵树,通常有助于递归 IMO:

 [] 1 2 3 []
 |         |
A []      C D
   |
  B C

所以也许在这里更清楚,我们必须同时连接递归的结果和向右取 "step" 的结果(再次递归),否则将是循环迭代数组.

var input = [['A',['B', 'C']],1,2,3,['C','D']]

function flat(array) {
    var result = []
    if (array.length == 0) return result;
  
    if (Array.isArray(array[0])) {
        result = result.concat(flat(array[0]));    // Step down
    } else {
        result.push(array[0]);
    }
    result = result.concat(flat(array.slice(1)))   // Step right

    return result;
}

console.log(flat(input));
// ["A", "B", "C", 1, 2, 3, "C", "D"]

这有点类似于带循环的版本:

function flat(array) {
    var result = []

    for (var i = 0; i < array.length; i++) {
        if (Array.isArray(array[i])) {
            result = result.concat(flat(array[i]));
        } else {
            result.push(array[i]);
        }
    }
    return result;
}

编辑:出于调试目的,您可以跟踪深度以帮助大致了解发生的情况:

var input = [['A',['B', 'C']],1,2,3,['C','D']]
function flat(array, depth) {
    var result = []
    if (array.length == 0) return result;

    if (Array.isArray(array[0])) {
        result = result.concat(flat(array[0], depth + 1));
    } else {
        result.push(array[0]);
    }
    var res1 = flat(array.slice(1), depth);
    console.log("Depth: " + depth + " | Concatenating: [" + result + "]  with: [" + res1 + "]");
    result = result.concat(res1)

    return result;
}

console.log(flat(input, 0));

如果您使用 JavaScript

,这是我的回答

您可以使用以下一行代码来展平 n 级嵌套数组

let flattendArray = input.flat(Infinity);

或者通过 reduce 和 concat 使用这种方法

function flatDeep(arr, d = 1) {
   return d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
                : arr.slice();
};

Refer this link