【问题标题】:Merge/flatten an array of arrays合并/展平数组数组
【发布时间】:2022-01-25 05:30:16
【问题描述】:

我有一个 JavaScript 数组,例如:

[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]

我将如何将单独的内部数组合并为一个:

["$6", "$12", "$25", ...]

【问题讨论】:

  • gist.github.com/Nishchit14/4c6a7349b3c778f7f97b912629a9f228 此链接描述 ES5 和 ES6 扁平化
  • 所有使用 reduce + concat 的解决方案都是 O((N^2)/2) ,其中作为可接受的答案(只需拨打 concat)最多O(N*2) 在一个坏的浏览器上和 O(N) 在一个好的浏览器上。此外,Denys 解决方案针对实际问题进行了优化,比单个 concat 快 2 倍。对于reduce 的人来说,编写小代码感觉很酷很有趣,但是例如,如果数组有 1000 个单元素子数组,那么所有 reduce+concat 解决方案都将执行500500 operations,而单个 concat 或简单循环将执行 1000 次操作。
  • 简单用户传播算子[].concat(...array)
  • @gman reduce + concat 解决方案 O((N^2)/2) 怎么样? stackoverflow.com/questions/52752666/… 提到了不同的复杂性。
  • 使用支持ES2019的最新浏览器:array.flat(Infinity),其中Infinity是展平的最大深度。

标签: javascript arrays multidimensional-array frontend flatten


【解决方案1】:

ES2019 在 Array Prototype 中引入了 .flat() 方法。您可以在 flat() 方法中传递“深度”参数来指定嵌套数组结构应该被展平的深度。默认为 1。

const twoDimensionsArray = [[1, 2, [3,4], {key: 'value'}], [5,6, {key: 'value'}]];

const oneDimensionArray = twoDimensionsArray.flat(2);

【讨论】:

    【解决方案2】:

    你可以使用"join()""split()"

    let arrs = [
      ["$6"],
      ["$12"],
      ["$25"],
      ["$25"],
      ["$18"],
      ["$22"],
      ["$10"]
    ];
    
    let newArr = arrs.join(",").split(",");
    
    console.log(newArr); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

    此外,您还可以使用 "toString()""split()"

    let arrs = [
      ["$6"],
      ["$12"],
      ["$25"],
      ["$25"],
      ["$18"],
      ["$22"],
      ["$10"]
    ];
    
    let newArr = arrs.toString().split(",");
    
    console.log(newArr); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

    但是,如果字符串包含逗号,上述两种方法都不能正常工作

    “join()”“split()”

    let arrs = [
      ["$,6"],
      ["$,12"],
      ["$2,5"],
      ["$2,5"],
      [",$18"],
      ["$22,"],
      ["$,1,0"]
    ];
    
    let newArr = arrs.join(",").split(",");
    
    console.log(newArr); 
    // ["$", "6", "$", "12", "$2", "5", "$2", "5", "", "$18", "$22", "", "$", "1", "0"]

    "toString()""split()"

    let arrs = [
      ["$,6"],
      ["$,12"],
      ["$2,5"],
      ["$2,5"],
      [",$18"],
      ["$22,"],
      ["$,1,0"]
    ];
    
    let newArr = arrs.toString().split(",");
    
    console.log(newArr); 
    // ["$", "6", "$", "12", "$2", "5", "$2", "5", "", "$18", "$22", "", "$", "1", "0"]

    【讨论】:

      【解决方案3】:

      如果你的编码环境支持 ES6 (ES2015),你不需要编写任何递归函数或使用 map、reduce 等数组方法。

      一个简单的spread operator (...) 将帮助您将一个数组数组扁平化为一个单个数组

      例如:

        const data = [[1, 2, 3], [4, 5],[2]]
        let res = []
        data.forEach(curSet=>{
            res = [...res,...curSet]
        })
        console.log(res) //[1, 2, 3, 4, 5, 2]
      

      【讨论】:

        【解决方案4】:

        简单的解决方案

        const firstRes = [
          ["$6"],
          ["$12"],
          ["$25"],
          ["$25"],
          ["$18"],
          ["$22"],
          ["$10"]
        ].flat()
        
        console.log(firstRes)
        ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]
        
        //
        
        const secondRes = [
          [["$6"]],
          [["$12"]],
          [["$25"]],
          [["$25"]]
        ].flat().flat()
        
        console.log(secondRes)
        ["$6", "$12", "$25", "$25"]
        
        

        【讨论】:

          【解决方案5】:

          var array = [["$6"], ["$12","$16"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
          var a = array.flat(Infinity);
          console.log(a);

          【讨论】:

            【解决方案6】:
            const arr = [1, 2, [3, 4]];
            
            arr.reduce((acc, val) => acc.concat(val), []);
            
            

            【讨论】:

              【解决方案7】:

              这是使用堆栈进行非递归展平深度的解决方案。

                  function flatten(input) {
                      const stack = [...input];
                      const res = [];
                      while (stack.length) {
                          const next = stack.pop();
                          if (Array.isArray(next)) {
                              stack.push(...next);
                          } else {
                              res.push(next);
                          }
                      }
                      return res.reverse();
                  }
                  const arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
                  flatten(arrays);
              

              【讨论】:

                【解决方案8】:

                我只是尝试在不使用任何内置函数的情况下解决问题。

                var arr = [1, 3, 4, 65, [3, 5, 6, 9, [354, 5, 43, 54, 54, 6, [232, 323, 323]]]];
                var result = [];
                
                function getSingleArray(inArr) {
                  for (var i = 0; i < inArr.length; i++) {
                    if (typeof inArr[i] == "object") {
                      getSingleArray(inArr[i]); // Calling Recursively
                    } else {
                      result.push(inArr[i]);
                    }
                  }
                }
                
                getSingleArray(arr);
                console.log(result); // [1, 3, 4, 65, 3, 5, 6, 9, 354, 5, 43, 54, 54, 6, 232, 323, 323]
                

                【讨论】:

                  【解决方案9】:

                  只需使用扩展运算符,我们就可以通过以下方式进行展平。

                  var OriginalArray = [[5, 1], [6], [2], [8]];
                  var newArray = [];
                  
                  for (let i = 0; i < OriginalArray.length; i++) {
                    newArray.push(...OriginalArray[i]);
                  }
                  
                  console.log(newArray)

                  【讨论】:

                    【解决方案10】:

                    有 2 种方法可以让你的数组变平

                    *1-第一个你可以使用Array.prototype.flat方法

                    const veryDeep = [[1, [2, 2, [3, [4, [5, [6]]]]], 1]];
                    
                    veryDeep.flat(Infinity)
                     // [1, 2, 2, 3, 4, 5, 6, 1]
                     /**  If you don't know the depth of the array, 
                    simply pass Infinity **\
                    

                    或者如果你知道你的数组有多少嵌套,你可以提出论据

                    const twoLevelsDeep = [[1, [2, 2], 1]];
                    //depth = 1
                    twoLevelsDeep.flat();
                    [1, [2, 2], 1]
                    
                    //depth = 2
                    twoLevelsDeep.flat(2);
                    // [1, 2, 2, 1]
                    

                    *在 ES6 中使用扩展运算符和 Concat 以 2 秒的方式展平数组,无论其中嵌套了多少个,它都会展平你的数组

                     const multidimension = [?, [?, ?, ?], ?, [?, ?]];
                    
                       [].concat(...multidimension); // This will return: [?, ?, ?, ?, ?, ?, 
                       ?]
                    
                       const multidimension = [1, [2, 3, 4], 5, [6, 7]];
                    
                       [].concat(...multidimension); // This will return: [1, 2, 3, 4, 5, 6, 7]
                    

                    【讨论】:

                      【解决方案11】:

                      您也可以尝试新的Array.flat() 方法。它的工作方式如下:

                      let arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]].flat()
                      
                      console.log(arr);

                      flat() 方法创建一个新数组,其中所有子数组元素递归连接到它的 1 层深度(即数组内的数组)

                      如果您还想展平 3 维甚至更高维的数组,您只需多次调用 flat 方法即可。例如(3 个维度):

                      let arr = [1,2,[3,4,[5,6]]].flat().flat().flat();
                      
                      console.log(arr);

                      小心!

                      Array.flat() 方法相对较新。像 ie 这样的旧浏览器可能没有实现该方法。如果您希望您的代码可以在所有浏览器上工作,您可能必须将您的 JS 转换为旧版本。检查 MDN web docs 以了解当前浏览器的兼容性。

                      【讨论】:

                      • 要扁平化高维数组,您只需使用 Infinity 参数调用 flat 方法。像这样:arr.flat(Infinity)
                      【解决方案12】:

                      这是 Typescript 中最快的解决方案,它也适用于具有多级嵌套的数组:

                      export function flatten<T>(input: Array<any>, output: Array<T> = []): Array<T> {
                          for (const value of input) {
                              Array.isArray(value) ? flatten(value, output) : output.push(value);
                          }
                          return output;
                      }
                      

                      比:

                      const result = flatten<MyModel>(await Promise.all(promises));
                      

                      【讨论】:

                        【解决方案13】:
                        function flatten(input) {
                          let result = [];
                          
                          function extractArrayElements(input) {
                            for(let i = 0; i < input.length; i++){
                              if(Array.isArray(input[i])){
                                extractArrayElements(input[i]);
                              }else{
                                result.push(input[i]);
                              }
                            }
                          }
                          
                          extractArrayElements(input);
                          
                          return result;
                        }
                        
                        
                        // let input = [1,2,3,[4,5,[44,7,8,9]]];
                        // console.log(flatten(input));
                        
                        // output [1,2,3,4,5,6,7,8,9]
                        

                        【讨论】:

                          【解决方案14】:

                          在Node环境下,如果你的版本不支持Array.prototype.flat,但是你使用的是es6或者ts,那么你可以这样做

                          const arrays = [
                            ["$6"],
                            ["$12"],
                            ["$25"],
                            ["$25"],
                            ["$18"],
                            ["$22"],
                            ["$10"]
                          ];
                          const merged = [].concat(...arrays);
                          
                          console.log(merged);

                          【讨论】:

                            【解决方案15】:

                            使用此方法将两个数组展平

                            arr1.concat(...arr2);
                            

                            【讨论】:

                              【解决方案16】:

                              使用 jQuery $.map() 函数的另一种方法。 来自 jQuery 文档:

                              该函数可以返回一个值数组,该数组将被展平成完整的数组。

                              var source = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
                              var target = $.map(source, function(value) { return value; }); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]
                              

                              【讨论】:

                                【解决方案17】:

                                您可以使用concat 来合并数组:

                                var arrays = [
                                  ["$6"],
                                  ["$12"],
                                  ["$25"],
                                  ["$25"],
                                  ["$18"],
                                  ["$22"],
                                  ["$10"]
                                ];
                                var merged = [].concat.apply([], arrays);
                                
                                console.log(merged);

                                使用concatapply方法只会将第二个参数作为一个数组,所以最后一行与此相同:

                                var merged2 = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);
                                

                                还有 Array.prototype.flat() 方法(在 ES2019 中引入),您可以使用它来展平数组,尽管 it is only available in Node.js starting with version 11, and not at all in Internet Explorer

                                const arrays = [
                                      ["$6"],
                                      ["$12"],
                                      ["$25"],
                                      ["$25"],
                                      ["$18"],
                                      ["$22"],
                                      ["$10"]
                                    ];
                                const merge3 = arrays.flat(1); //The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
                                console.log(merge3);
                                    

                                【讨论】:

                                • 注意concat不会修改源数组,所以merged数组在调用concat后会保持为空。最好这样说:merged = merged.concat.apply(merged, arrays);
                                • var merged = [].concat.apply([], arrays); 似乎可以很好地将它放在一条线上。编辑:正如尼基塔的回答已经表明的那样。
                                • Array.prototype.concat.apply([], arrays)
                                • 注意:这个答案只会变平一层。对于递归展平,请参阅@Trindaz 的答案。
                                • 对@Sean 的进一步评论:ES6 语法使这个超级简洁:var merged = [].concat(...arrays)
                                【解决方案18】:

                                这里是递归方式...

                                function flatten(arr){
                                    let newArray = [];
                                    for(let i=0; i< arr.length; i++){
                                        if(Array.isArray(arr[i])){
                                          newArray =  newArray.concat(flatten(arr[i]))
                                        }else{
                                          newArray.push(arr[i])
                                        }
                                    }
                                  return newArray; 
                                }
                                
                                console.log(flatten([1, 2, 3, [4, 5] ])); // [1, 2, 3, 4, 5]
                                console.log(flatten([[[[1], [[[2]]], [[[[[[[3]]]]]]]]]]))  // [1,2,3]
                                console.log(flatten([[1],[2],[3]])) // [1,2,3]
                                

                                【讨论】:

                                  【解决方案19】:

                                  使用扩展运算符:

                                  const input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
                                  const output = [].concat(...input);
                                  console.log(output); // --> ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

                                  【讨论】:

                                    【解决方案20】:

                                    我认为 array.flat(Infinity) 是一个完美的解决方案。但是平面函数是一个比较新的函数,可能无法在旧版本的浏览器中运行。我们可以使用递归函数来解决这个问题。

                                    const arr = ["A", ["B", [["B11", "B12", ["B131", "B132"]], "B2"]], "C", ["D", "E", "F", ["G", "H", "I"]]]
                                    const flatArray = (arr) => {
                                        const res = []
                                        for (const item of arr) {
                                            if (Array.isArray(item)) {
                                                const subRes = flatArray(item)
                                                res.push(...subRes)
                                            } else {
                                                res.push(item)
                                            }
                                        }
                                    
                                        return res
                                    }
                                    
                                    console.log(flatArray(arr))

                                    【讨论】:

                                    • 谢谢刚才面试官问了我同样的问题。
                                    【解决方案21】:

                                    使用单行代码解决此问题..

                                    function unflatten(arr){
                                        return arr.reduce((prevProps, nextProps) => {
                                            return prevProps.concat(Array.isArray(nextProps) ? unflatten(nextProps) : nextProps)
                                        }, [])
                                    }

                                    https://codepen.io/jyotishman/pen/BayVeoQ

                                    【讨论】:

                                      【解决方案22】:

                                      此解决方案适用于数组的任何深度级别(指定嵌套数组结构的深度)。

                                      function flatten(obj) {
                                          var out = [];
                                          function cleanElements(input) {
                                              for (var i  in input){
                                                  if (input[i]instanceof Array){
                                                      cleanElements(input[i]);
                                                  }
                                                  else {
                                                      out.push(input[i]);
                                                  }
                                              }
                                          }
                                          cleanElements(obj);
                                          return (out);
                                      }
                                      

                                      【讨论】:

                                        【解决方案23】:

                                        有一个名为flat 的新本机方法可以完全做到这一点。

                                        (截至 2019 年底,flat 现在已在 ECMA 2019 标准中发布,core-js@3(babel 的库)将其包含在他们的 polyfill library 中)

                                        const arr1 = [1, 2, [3, 4]];
                                        arr1.flat(); 
                                        // [1, 2, 3, 4]
                                        
                                        const arr2 = [1, 2, [3, 4, [5, 6]]];
                                        arr2.flat();
                                        // [1, 2, 3, 4, [5, 6]]
                                        
                                        // Flatten 2 levels deep
                                        const arr3 = [2, 2, 5, [5, [5, [6]], 7]];
                                        arr3.flat(2);
                                        // [2, 2, 5, 5, 5, [6], 7];
                                        
                                        // Flatten all levels
                                        const arr4 = [2, 2, 5, [5, [5, [6]], 7]];
                                        arr4.flat(Infinity);
                                        // [2, 2, 5, 5, 5, 6, 7];
                                        

                                        【讨论】:

                                        • 很遗憾,这甚至不在答案的第一页。此功能在 Chrome 69 和 Firefox 62 中可用(以及在后端工作的 Node 11)
                                        • -1;不,这不是ECMAScript 2018 的一部分。它仍然只是一个尚未成为任何 ECMAScript 规范的提案。
                                        • 我认为现在我们可以考虑这个 .. 因为现在它是标准 (2019) 的一部分 .. 我们可以重新审视一下它的性能部分吗?
                                        • 似乎还没有任何微软浏览器支持它(至少在我写这篇评论的时候)
                                        【解决方案24】:

                                        递归调用deepFlatten 函数,这样我们就可以在不使用任何外部辅助方法的情况下扩展内部数组。

                                        const innerArr = ['a', 'b'];
                                        const multiDimArr = [[1, 2], 3, 4, [5, 6, innerArr], 9];
                                        
                                        const deepFlatten = (arr) => {
                                          const flatList = [];
                                          arr.forEach(item => {
                                            Array.isArray(item)
                                             ? flatList.push(...deepFlatten(item)) // recursive call
                                             : flatList.push(item)
                                          });
                                          return flatList;
                                        }
                                        

                                        【讨论】:

                                          【解决方案25】:

                                          由于 ES2019 引入了 flat 和 flatMap,那么 flat 任何数组都可以这样完成:

                                          const myArr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
                                          const myArrFlat= myArr.flat(Infinity);
                                          console.log(myArrFlat); // ["$6", "$12", "$25", ...]
                                          

                                          参考。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

                                          【讨论】:

                                            【解决方案26】:

                                            您可以将Array.flat()Infinity 一起用于任何深度的嵌套数组。

                                            var arr = [ [1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]], [[1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]]] ];
                                            
                                            let flatten = arr.flat(Infinity)
                                            
                                            console.log(flatten)

                                            在此处查看浏览器compatibility

                                            【讨论】:

                                              【解决方案27】:

                                              如果你使用 lodash,你可以使用它的 flatten 方法:https://lodash.com/docs/4.17.14#flatten

                                              lodash 的好处在于它还有扁平化数组的方法:

                                              i) 递归:https://lodash.com/docs/4.17.14#flattenDeep

                                              ii) 最多 n 层嵌套:https://lodash.com/docs/4.17.14#flattenDepth

                                              例如

                                              const _ = require("lodash");
                                              const pancake =  _.flatten(array)
                                              

                                              【讨论】:

                                                【解决方案28】:

                                                我写的简单的扁平化工具

                                                const flatten = (arr, result = []) => {
                                                    if (!Array.isArray(arr)){
                                                        return [...result, arr];
                                                    }
                                                     arr.forEach((a) => {
                                                         result = flatten(a, result)
                                                    })
                                                
                                                    return result
                                                }
                                                
                                                console.log(flatten([1,[2,3], [4,[5,6,[7,8]]]])) // [ 1, 2, 3, 4, 5, 6, 7, 8 ]
                                                

                                                【讨论】:

                                                  【解决方案29】:

                                                  ES-Next 解决方案

                                                  1. Array.from / Set / Array.flat / Array.sort
                                                  // 1. remove duplicate item
                                                  // 2. flat array
                                                  let arr= [["$6", ["$18"]], ["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
                                                  
                                                  let result = Array.from(new Set(arr.flat(Infinity)));
                                                  
                                                  console.log(`flat array with unique filter`, result);
                                                  // 
                                                  
                                                  

                                                  // 1. remove duplicate item
                                                  // 2. sort by Asc order (munber only)
                                                  // 3. flat array
                                                  
                                                  // let arr= [["$6", ["$18"]], ["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
                                                  
                                                  let arr= [["6", ["18"]], ["6"], ["12"], ["25"], ["25"], ["18"], ["22"], ["10"]];
                                                  
                                                  let result = Array.from(new Set(arr.flat(Infinity))).map(Number).sort((a,b)=> a > b ? 1: -1);
                                                  
                                                  console.log(`flat array with unique filter & Asc sort`, result);
                                                  //
                                                  1. ...展开/设置/Array.flat/Array.sort
                                                  // 1. remove duplicate item
                                                  // 2. flat array
                                                  let arr= [["$6", ["$18"]], ["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
                                                  
                                                  let result = [...new Set(arr.flat(Infinity))];
                                                  
                                                  console.log(`flat array with unique filter`, result);
                                                  // 
                                                  
                                                  

                                                  // 1. remove duplicate item
                                                  // 2. sort by Asc order(number only)
                                                  // 3. flat array
                                                  
                                                  //let arr= [["$6", ["$18"]], ["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
                                                  
                                                  let arr= [["6", ["18"]], ["6"], ["12"], ["25"], ["25"], ["18"], ["22"], ["10"]];
                                                  
                                                  let result = [...new Set(arr.flat(Infinity))].map(Number).sort((a,b)=> a > b ? 1: -1);
                                                  
                                                  console.log(`flat array with unique filter & Asc sort`, result);
                                                  // 

                                                  参考

                                                  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/

                                                  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

                                                  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

                                                  【讨论】:

                                                    【解决方案30】:

                                                    在 javascript 中定义一个名为 foo 的数组数组,并使用 javascript 的数组 concat 内置方法将该数组扁平化为单个数组:

                                                    const foo = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]] 
                                                    console.log({foo}); 
                                                    
                                                    const bar = [].concat(...foo) 
                                                    console.log({bar});
                                                    

                                                    应该打印:

                                                    { foo: 
                                                       [ [ '$6' ],
                                                         [ '$12' ],
                                                         [ '$25' ],
                                                         [ '$25' ],
                                                         [ '$18' ],
                                                         [ '$22' ],
                                                         [ '$10' ] ] }
                                                    { bar: [ '$6', '$12', '$25', '$25', '$18', '$22', '$10' ] }
                                                    

                                                    【讨论】:

                                                      猜你喜欢
                                                      • 1970-01-01
                                                      • 2017-07-05
                                                      • 1970-01-01
                                                      • 1970-01-01
                                                      • 2010-09-09
                                                      • 1970-01-01
                                                      • 2020-05-07
                                                      相关资源
                                                      最近更新 更多