Javascript递归数组展平

时间:2015-05-05 08:56:28

标签: javascript arrays recursion

我正在练习并尝试编写递归数组展平函数。代码在这里:

if (item <= 10)
{
    money += 25;
    $('#money').html(money);
}
else if (item > 10 && item <= 20)
{
    money += 50;
    $('#money').html(money);
}

问题是,如果我在那里传递一个数组或嵌套数组,我会得到&#34;超过最大调用堆栈大小&#34;错误。我做错了什么?

21 个答案:

答案 0 :(得分:20)

问题是你如何传递数组的处理,如果值是一个数组,那么你一直在调用它导致无限循环

barButtonItem

演示:Fiddle

这是一个更现代的版本:

function flatten() {
    var flat = [];
    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] instanceof Array) {
            flat.push.apply(flat, flatten.apply(this, arguments[i]));
        } else {
            flat.push(arguments[i]);
        }
    }
    return flat;
}

答案 1 :(得分:3)

[...arr.toString().split(",")]

使用toString()的{​​{1}}方法。使用扩展运算符Object制作一个字符串数组,并用(...)分割它。

示例:

","

答案 2 :(得分:3)

Haskellesque方法......

function flatArray([x,...xs]){
  return x !== undefined ? [...Array.isArray(x) ? flatArray(x) : [x],...flatArray(xs)]
                         : [];
}

var na = [[1,2],[3,[4,5]],[6,7,[[[8],9]]],10];
    fa = flatArray(na);
console.log(fa);

答案 3 :(得分:2)

您的代码缺少else语句,并且递归调用不正确(您反复传递相同的数组而不是传递其项目。)

您的功能可以这样写:

if (long.TryParse(mystringnumber,null))
{
dosomething();
}

答案 4 :(得分:2)

如果你假设你的第一个参数是一个数组,那么你可以很简单。

function flatten(a) {
    return a.reduce((flat, i) => {
      if (Array.isArray(i)) {
        return flat.concat(flatten(i));
      }
      return flat.concat(i);
    }, []);
  }

如果您确实想要展平多个数组,只需在传递之前将它们连接起来。

答案 5 :(得分:2)

如果项目是数组,我们只需将所有剩余项目添加到此数组

function flatten(array, result) {
  if (array.length === 0) {
    return result
  }
  var head = array[0]
  var rest = array.slice(1)
  if (Array.isArray(head)) {
    return flatten(head.concat(rest), result)
  }
  result.push(head)
  return flatten(rest, result)
}

console.log(flatten([], []))
console.log(flatten([1], []))
console.log(flatten([1,2,3], []))
console.log(flatten([1,2,[3,4]], []))
console.log(flatten([1,2,[3,[4,5,6]]], []))
console.log(flatten([[1,2,3],[4,5,6]], []))
console.log(flatten([[1,2,3],[[4,5],6,7]], []))
console.log(flatten([[1,2,3],[[4,5],6,[7,8,9]]], []))

答案 6 :(得分:1)

如果有人在寻找扁平的对象数组(例如tree),那么这里是代码:

&#13;
&#13;
function flatten(items) {
  const flat = [];

  items.forEach(item => {
    flat.push(item)
    if (Array.isArray(item.children) && item.children.length > 0) {
      flat.push(...flatten(item.children));
      delete item.children
    }
    delete item.children
  });

  return flat;
}

var test = [
	{children: [
      {children: [], title: '2'}
      ],
  title: '1'},
	{children: [
      {children: [], title: '4'},
      {children: [], title: '5'}
      ],
  title: '3'}
]

console.log(flatten(test))
&#13;
&#13;
&#13;

答案 7 :(得分:1)

2019 中使用 ES6 展平阵列的干净方法是flat()

const array = [1, 1, [2, 2], [[3, [4], 3], 2]]

// All layers
array.flat(Infinity) // [1, 1, 2, 2, 3, 4, 3, 2]

// Varying depths
array.flat() // [1, 1, 2, 2, Array(3), 2]

array.flat(2) // [1, 1, 2, 2, 3, Array(1), 3, 2]
array.flat().flat() // [1, 1, 2, 2, 3, Array(1), 3, 2]

array.flat(3) // [1, 1, 2, 2, 3, 4, 3, 2]
array.flat().flat().flat() // [1, 1, 2, 2, 3, 4, 3, 2]

Mozilla Docs

Can I Use-2019年11月为84%

答案 8 :(得分:1)

这是我的实用方法:

const deepFlatten = (array => (array, start = []) => array.reduce((acc, curr) => {
    return Array.isArray(curr) ? deepFlatten(curr, acc) : [...acc, curr];
}, start))();

console.log(deepFlatten([[1,2,[3, 4, [5, [6]]]],7]));

答案 9 :(得分:0)

现代而不是跨浏览器

function flatten(arr) {
  return arr.flatMap(el => {
    if(Array.isArray(el)) {
        return flatten(el)
    } else {
      return el;
    }
})

}

答案 10 :(得分:0)

有几种方法可以做到这一点:

  1. 使用 flat 方法和 Infinity 关键字:

    const flattened = arr.flat(Infinity);

  2. 您可以使用 reduce 和 concat 方法来展平任何数组,如下所示:

    function flatten(arr) { return arr.reduce((acc, cur) => acc.concat(Array.isArray(cur) ? flatten(cur) : cur), []); };

阅读更多信息: https://www.techiedelight.com/recursively-flatten-nested-array-javascript/

答案 11 :(得分:0)

我已经在 stackoverflow 中的 this page 上发布了我的数组展平的递归版本。

答案 12 :(得分:0)

下面的函数对数组进行扁平化处理,并保留每个项目的类型,而不是将它们更改为字符串。如果您需要扁平化不只包含数字之类的数组,这将非常有用。它可以扁平化任何类型的数组,没有副作用。

function flatten(arr) {
  for (let i = 0; i < arr.length; i++) {
    arr = arr.reduce((a, b) => a.concat(b),[])
  }
  return arr
}

console.log(flatten([1, 2, [3, [[4]]]]));
console.log(flatten([[], {}, ['A', [[4]]]]));

答案 13 :(得分:0)

我认为问题在于您使用 arguments 的方式。

既然你说传递嵌套数组时,会导致“最大调用堆栈大小超出”错误。

因为 arguments[0] 是指向您传递给 flatten 函数的第一个参数的引用。例如:

   flatten([1,[2,[3]]]) // arguments[0] will always represents `[1,[2,[3]]]`

因此,您的代码最终会使用相同的参数一次又一次地调用 flatten

要解决这个问题,我认为最好使用named arguments,而不是使用arguments,后者本质上不是“真正的数组”。

答案 14 :(得分:0)

我希望你能有所不同。一种结合了递归和“for循环”/高阶函数。我想在没有 for 循环或高阶函数的情况下回答。

再次检查数组的第一个元素是否为数组。如果是,请递归直到到达最里面的数组。然后推到结果。我希望我以纯粹的递归方式接近它。

function flatten(arr, result = []) {
  if(!arr.length) return result;
  (Array.isArray(arr[0])) ? flatten(arr[0], result): result.push(arr[0]);
  return flatten(arr.slice(1),result)
}

答案 15 :(得分:0)

在JavaScript中扁平化数组的递归方法如下。

function flatten(array) {
    let flatArray = [];
    for (let i = 0; i < array.length; i++) {
        if (Array.isArray(array[i])) {
            flatArray.push(...flatten(array[i]));
        } else {
            flatArray.push(array[i]);
        }
    }
    return flatArray;
}

let array = [[1, 2, 3], [[4, 5], 6, [7, 8, 9]]];
console.log(flatten(array));    
// Output = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

let array2 = [1, 2, [3, [4, 5, 6]]];
console.log(flatten(array2));    
// Output = [ 1, 2, 3, 4, 5, 6 ]

答案 16 :(得分:0)

这应该有效

function flatten() {
    var flat = [
    ];
    for (var i = 0; i < arguments.length; i++) {
        flat = flat.concat(arguments[i]);
    }
    var removeIndex = [
    ];
    for (var i = flat.length - 1; i >= 0; i--) {
        if (flat[i] instanceof Array) {
            flat = flat.concat(flatten(flat[i]));
            removeIndex.push(i);
        }
    }
    for (var i = 0; i < removeIndex.length; i++) {
        flat.splice(removeIndex - i, 1);
    }
    return flat;
}

答案 17 :(得分:0)

这是从 absurdum 采取的递归化简实现,它模仿lodash的_.concat()

它可以接受任意数量的数组或非数组参数。数组可以是任意深度。结果输出将是一个单一的平坦值数组。

export const concat = (...arrays) => {
  return flatten(arrays, []);
}

function flatten(array, initial = []) {
  return array.reduce((acc, curr) => {
    if(Array.isArray(curr)) {
      acc = flatten(curr, acc);
    } else {
      acc.push(curr);
    }
    return acc;
  }, initial);
}

它可以接受任意数量的数组或非数组值作为输入。

来源:我是荒诞派的作者

答案 18 :(得分:0)

这是针对此问题的Vanilla JavaScript解决方案

&#13;
&#13;
var _items = {'keyOne': 'valueOne', 'keyTwo': 'valueTwo', 'keyThree': ['valueTree', {'keyFour': ['valueFour', 'valueFive']}]};

// another example
// _items = ['valueOne', 'valueTwo', {'keyThree': ['valueTree', {'keyFour': ['valueFour', 'valueFive']}]}];

// another example
/*_items = {"data": [{
    "rating": "0",
    "title": "The Killing Kind",
    "author": "John Connolly",
    "type": "Book",
    "asin": "0340771224",
    "tags": "",
    "review": "i still haven't had time to read this one..."
}, {
    "rating": "0",
    "title": "The Third Secret",
    "author": "Steve Berry",
    "type": "Book",
    "asin": "0340899263",
    "tags": "",
    "review": "need to find time to read this book"
}]};*/

function flatten() {
    var results = [],
        arrayFlatten;

    arrayFlatten = function arrayFlattenClosure(items) {
        var key;
        
        for (key in items) {
            if ('object' === typeof items[key]) {
                arrayFlatten(items[key]);
            } else {
                results.push(items[key]);
            }
        }
    };

    arrayFlatten(_items);
    
    return results;
}

console.log(flatten());
&#13;
&#13;
&#13;

答案 19 :(得分:0)

其他答案已经指出了OP代码故障的根源。编写更多描述性代码,问题实际上归结为“array-detection / -reduce / -concat-recursion”......

(function (Array, Object) {


//"use strict";


  var
    array_prototype       = Array.prototype,

    array_prototype_slice = array_prototype.slice,
    expose_internal_class = Object.prototype.toString,


    isArguments = function (type) {
      return !!type && (/^\[object\s+Arguments\]$/).test(expose_internal_class.call(type));
    },
    isArray     = function (type) {
      return !!type && (/^\[object\s+Array\]$/).test(expose_internal_class.call(type));
    },

    array_from  = ((typeof Array.from == "function") && Array.from) || function (listAlike) {
      return array_prototype_slice.call(listAlike);
    },


    array_flatten = function flatten (list) {
      list = (isArguments(list) && array_from(list)) || list;

      if (isArray(list)) {
        list = list.reduce(function (collector, elm) {

          return collector.concat(flatten(elm));

        }, []);
      }
      return list;
    }
  ;


  array_prototype.flatten = function () {
    return array_flatten(this);
  };


}(Array, Object));

借用其他答案之一的代码作为概念证据......

console.log([
  [[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]],
  [[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]]
].flatten());
//[0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, ..., ..., ..., 0, 1, 2]

答案 20 :(得分:-1)

你应该为递归添加停止条件。

作为一个例子 如果len(arguments [i])== 0返回