扁平化多个嵌套数组的数组而不带递归 - javascript

Flatten array of multiple nested arrays without recursion - javascript

本文关键字:数组 递归 javascript 嵌套 扁平化      更新时间:2023-09-26

也许这是一个愚蠢的问题,但我无法意识到是否可以在没有递归的情况下展平多维数组

我有一个我用递归编写的解决方案:

function transform (arr) {
   var result = [];
   arr.forEach(flatten)
   function flatten (el) {
     if (Array.isArray(el)) {
        return el.forEach(flatten);
     }
     return result.push(el);
   }
   return result;
}

要展平的数组示例:

[1, {a: [2, 3]}, 4, [5, [6]], [[7], 8, 9], 10]

和执行:

var a = [1, {a: [2, 3]}, 4, [5, [6]], [[7], 8, 9], 10];
var r = transform(r);
console.log(r); // [1, {a: [2, 3]}, 4, 5, 6, 7, 8, 9, 10]

谢谢!

您可以使用堆栈。当您发现嵌套数组时,只需将其替换为其项即可。

function flatten(arr) {
  var result = [];
  var stack = arr, first;
  while (stack.length > 0) {
    first = stack[0];
    if (Array.isArray(first)) {
      // Replace the nested array with its items
      Array.prototype.splice.apply(stack, [0, 1].concat(first));
    } else {
      result.push(first);
      // Delete the first item
      stack.splice(0, 1);
    }
  }
  return result;
}
我在

面试中遇到了完全相同的问题,并提出了这个解决方案:

function flattenNonRecursion(arr) {
  const res = arr.slice();
  let i = 0;
  while (i < res.length) {
    if (Array.isArray(res[i])) {
      res.splice(i, 1, ...res[i]);
    }
    else {
      i++;
    }
  }
  return res;
}
console.log(flattenNonRecursion([1, {a: [2, 3]}, 4, [5, [6]], [[7], 8, 9], 10]));
// [1, {a: [2, 3]}, 4, 5, 6, 7, 8, 9, 10]

所以,主要思想是我们正在通过我们的数组前进,如果我们遇到一个数组,我们会用它的内容替换它并继续前进......此解决方案的复杂性为 O(n)。

这里是 O(N) 解决方案,其中 N 是平展数组中的项目数,而不会改变输入数组。

对我来说,当我们使用

堆栈时,使用弹出和推送似乎更自然。该解决方案不使用非常昂贵的拼接、取消移位、移位和其他就地阵列突变方法。

使用 ES6 点差运算符,虽然不是必须的,可以用 apply 代替。

function flat(input) {
  const stack = [...input];
  const res = [];
  while (stack.length) {
    // pop value from stack
    const next = stack.pop();
    if (Array.isArray(next)) {
      // push back array items, won't modify the original input
      stack.push(...next);
    } else {
      res.push(next);
    }
  }
  return res.reverse();
}

您必须通过其他方式管理状态。

在这里,我使用数组来做到这一点。它让我们跟踪我们在我们正在做的事情的整体计划中的位置。我觉得我做得相当没有吸引力,但工作已经完成。

function transform(arr){
    var state = [];
    var i = 0,
        a = arr;
    var result = [];
    while(true){
        var val = a[i];
        if(Array.isArray(val)){
            state.push({i: i, a: a});
            a = val;
            i = -1;
        } else if (val !== undefined) {
            result.push(val)   
        }
        if(i++ >= a.length - 1){
            if(state.length > 0)
            {
                var s = state.pop();
                a = s.a;
                i = s.i + 1;
            } else {
                break;   
            }
        }
    }
    return result;
}
var a = [1, {a: [2, 3]}, 4, [5, [6]], [[7], 8, 9], 10];
console.log(a); // Chrome Outputs: [1, Object, 4, Array[2], Array[3], 10]
var r = transform(a);
console.log(r); // Chrome Outputs: [1, Object, 4, 5, 6, 7, 8, 9, 10]
function flat(arr) {
  for (let i= 0; i<arr.length; i++) {
    const element = arr[i];
    if (Array.isArray(element)) {
      arr.splice(i, 1, ...element); // replaces arr[i] with its elements
    }
  }
  return arr;
}

这是非递归 + 就地数组修改(不创建新数组)

我稍微

简化了@Misha的解决方案:

function flatten(array) {
  var result = []; 
  var stack = array
  var item;
  while (stack.length) {
    item = stack.shift();
    if (Array.isArray(item)) [].unshift.apply(stack, item);
    else result.push(item);
  }
  return result;
}

我们可以为此使用 JS Array flat() 方法,截至 2019 年 5 月,除 IE 外,大多数浏览器目前都支持这种方法。

语法

var newArray = arr.flat([depth]);

深度:可选

指定嵌套数组结构应展平的深度的深度级别。默认值为 1。

<小时 />

平展嵌套数组

一级深度:

const arr1 = [1, 2, [3, 4]]
const flattenArr = arr1.flat()
console.log(flattenArr)
// [1, 2, 3, 4]

<小时 />

两级深度:

const arr2 = [1, 2, [3, 4, [5, 6]]];
const flattenArr = arr2.flat(2)   // <== using 2 here
console.log(flattenArr)
// [1, 2, 3, 4, [5, 6]]

任何深度级别:

const arr3 = [1, {a: [2, 3]}, 4, [5, [6]], [[7], 8, 9], 10]
// Using `Infinity` here to flatten any depth level array
// For this use case we could have also used 3 here
const flattenArr = arr3.flat(Infinity)
console.log(flattenArr)
// [1, {a: [2, 3]}, 4, 5, 6, 7, 8, 9, 10]
.as-console-wrapper { max-height: 100%!important; }

这是一个使用两个数组来展平另一个数组的建议。

基本上,一个数组将计数保持在某个级别,另一个数组保留对具有级别的数组的引用。

与其他两种解决方案相比,主要优点是一次性使用 Array#push,而没有其他 Array 的变异方法。

function transform(array) {
    var result = [],
        level = 0,
        reference = [array],
        counter = [0];
    while (level >= 0) {
        if (counter[level] >= reference[level].length) {
            level--;
            continue;
        }
        if (Array.isArray(reference[level][counter[level]])) {
            reference[level + 1] = reference[level][counter[level]]
            counter[level]++;
            level++;
            counter[level] = 0;
            continue;
        }
        result.push(reference[level][counter[level]]);
        counter[level]++;
    }
    return result;
}
var a = [1, { a: [2, 3] }, 4, [5, [6]], [[7], 8, 9], 10],
    r = transform(a);
console.log(r);

const flatten = (array) => {
  const flattenedArray = []; // an empty array that all flattened elements will be in
  while(array.length) { // while there are still elements in the array
    const ele = array.shift(); // remove the first element 
    if(!Array.isArray(ele)) { // check if this element is not an array
        flattenedArray.push(ele); // since it's not, just push it into the flattened array
        continue; // continue to do this to all non arrays and ignore the rest of the code until...
      };
      array = [...ele,...array]; // you've found an array in your given array, now you get all the elements of the array you just found, with the rest operator, put them all into a new array, with the remaining elements of the main array at it's back with also the rest operator, make it equal to the original array
  };
  return flattenedArray; // return the flattened array
};
// This is less problematic and straight forward, because all the elements previously removed that are not arrays continue to leave the main array into the flattened array 
const ar =[1,2,[3,[4,5,[6,7,[8,9]]]]]
 function singleArray(ar) {
 return ar.reduce((ac, cur) =>{
   if(Array.isArray(cur)){
     return [...ac, ...singleArray(cur)]
   }
   return [...ac, cur];
 },[])
}
console.log(singleArray(ar)) 
const getFalttenArrayWithInArrayModification = (arr) => {
    for (let i = 0; i < arr.length; i++) {
      if (Array.isArray(arr[i])) {
        arr.splice(i, 1, ...arr[i]);
        if (Array.isArray(arr[i])) 
          i--;
      }
    }
    return arr;
}
const input = [[[[2,5],6], [4,5]], 5, [[4,5], 3, [9,8]]];
console.log(getFalttenArrayWithInArrayModification(input));

答案是对 Skay 答案几乎没有修改,因为这没有处理第一个替换元素是数组的用例。