【问题标题】:Flatten array of multiple nested arrays without recursion - javascript展平多个嵌套数组的数组而无需递归 - javascript
【发布时间】:2015-02-02 21:13:10
【问题描述】:

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

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

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]

谢谢!

【问题讨论】:

  • 为什么不想使用递归?
  • @JoeEnos 更多的是关于自我教育和好奇心。
  • 只有数组很容易,但包括不确定的对象
  • @juvian 有多容易?使用[].concat.apply([], arr); 不会解决多个嵌套的问题:/
  • var a = [1, 4, [5, [6]], [[[5],[6],[[7]]], 8, 9], 10];console.log(a.toString().split(','))

标签: javascript arrays flatten


【解决方案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】:

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

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

    【讨论】:

    • , first 是干什么用的?
    • 我建议您只需要 else 子句中的这一行:result.push(stack.splice(0, 1)[0]) 从堆栈中删除第一项并将其推送到结果数组。干杯
    【解决方案3】:

    这是一个使用两个数组来展平另一个数组的提案。

    基本上一个数组保持一定级别的计数,另一个保持对数组的引用与级别。

    相对于其他两种解决方案的主要优势是 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);

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 这个解决方案比公认的更干净,谢谢!
      【解决方案5】:

      我稍微简化了@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】:

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

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

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

        【讨论】:

        • 我喜欢这种方法
        【解决方案7】:

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

        【讨论】:

          【解决方案8】:
          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;
          }
          
          

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

          【讨论】:

            猜你喜欢
            • 2015-08-15
            • 1970-01-01
            • 2015-07-14
            • 2018-04-20
            • 1970-01-01
            • 2018-11-13
            • 1970-01-01
            • 2020-07-15
            • 1970-01-01
            相关资源
            最近更新 更多