在没有递归的情况下展平多个嵌套数组的数组 - javascript

时间:2014-12-04 20:26:14

标签: javascript arrays flatten

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

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

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]

谢谢!

7 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:1)

你必须通过其他方式管理国家。

这里我用数组做。它让我们可以跟踪我们在整体方案中所处的位置。我觉得我这样做相当没有吸引力,但工作已经完成。

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]

答案 2 :(得分:1)

我在采访中得到了完全相同的问题,并提出了这个解决方案:

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

答案 3 :(得分:1)

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

当我们使用堆栈时,似乎更自然地使用pop和push。此解决方案不使用非常昂贵的剪接,不移位,移位和其他就地数组变异方法。

虽然不是必须的,但可以使用apply来代替使用ES6扩展运算符。

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

答案 4 :(得分:0)

这是一个使用两个数组来压扁另一个数组的提案。

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

与其他两个解决方案相比的主要优势是单独使用Array#push而没有其他类似的数据删除方法。

&#13;
&#13;
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);
&#13;
&#13;
&#13;

答案 5 :(得分:0)

我简化了@ 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;
}

答案 6 :(得分:0)

我们可以为此使用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; }