Javascript:使用递归就地展平多维数组
Javascript: Flatten multidimensional array in place using recursion
我有以下代码可以展平多维数组
var x = [[[2, 3], 4], 5, [6, 7]];
function flatten(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].constructor === Array) {
subArr = arr[i];
// Shift the array down based on the space needed for the sub array
for (var j = arr.length + subArr.length - 2; j > i + subArr.length - 1; j--) {
arr[j] = arr[j - subArr.length + 1];
}
// Insert sub array elements where they belong
for (var k = 0; k < subArr.length; k++) {
arr[i + k] = subArr[k];
}
// Look at arr[i] again in case the first element in the subarray was another array;
i--;
}
}
}
flatten(x);
这里是 JSBin:http://jsbin.com/gazagemabe/edit?js,console
我想用递归来做这个,但我最终卡住了。我试图在不保留临时数组的情况下做到这一点,但事情似乎变得不正常了。我觉得我缺少递归的一些核心原则。
我意识到我需要一个基本案例。我能想到的唯一情况是当前处于展平状态的数组没有子数组。但是因为我总是通过引用传递数组,所以我没有什么可以 return.
我的伪代码是
function flatten(arr)
loop through arr
if arr[index] is an array
increase the array length arr[index] length
flatten(arr[index])
else
// unsure what to do here to modify the original array
这是一个完全就地工作的纯递归版本,不构建中间数组。
// Deep-flatten an array starting at index `i`.
function flatten(a, i = 0) {
if (i >= a.length)
// Null case--we are off the end of the array.
return;
var elt = a[i];
if (!Array.isArray(elt))
// Element is not an array. Proceed to next element.
i++;
else
// Element is an array.
// Unroll non-empty arrays; delete empty arrays.
if (elt.length) {
// Non-empty array.
// Unroll it into head and tail.
// Shift elements starting at `i` towards end of array.
// Have to do this recursively too--no loops!
(function shift(a, i, n = a.length) {
if (n > i ) a[n] = a[n-1], shift(a, i, --n);
}(a, i));
// Replace elt with its head, and place tail in slot we opened up.
a[i] = elt.shift();
a[i + 1] = elt;
}
else
// Array is empty.
// Delete the element and move remaining ones toward beginning of array.
// Again, have to do this recursively!
(function unshift(a, i) {
if (i < a.length) a[i] = a[i+1], unshift(a, ++i);
else a.length--;
}(a, i));
flatten(a, i);
}
var arr = [[[2, 3], 4], 5, [6, 7]];
flatten(arr);
console.log(arr);
[2, 3, 4, 5, 6, 7]
这个解决方案使用了ES6的点点滴滴,比如默认函数参数和Array.isArray
。如果您没有可用的 ES6,请相应地进行调整。
从内到外进行递归展平。首先对您找到的数组调用 flatten
函数,然后将该数组(现在是扁平的)的内容移动到父数组中。通过数组向后循环,这样您就不必为插入的项目调整循环变量。
如您所知,您插入的数组是平面的,您可以使用 splice
方法用其项目替换数组。
它是这样工作的:
start with
[[[2, 3], 4], 5, [6, 7]]
flatten [6,7] (which is already flat) and insert:
[[[2, 3], 4], 5, 6, 7]
flatten [[2, 3], 4] recursively calls flatten [2,3] and inserts in that array:
[[2, 3, 4], 5, 6, 7]
then it inserts [2, 3, 4]:
[2, 3, 4, 5, 6, 7]
代码:
function flatten(arr) {
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i].constructor === Array) {
flatten(arr[i]);
Array.prototype.splice.apply(arr, [i, 1].concat(arr[i]));
}
}
}
var x = [[[2, 3], 4], 5, [6, 7]];
flatten(x);
// Show result in snippet
document.write(JSON.stringify(x));
我有以下代码可以展平多维数组
var x = [[[2, 3], 4], 5, [6, 7]];
function flatten(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].constructor === Array) {
subArr = arr[i];
// Shift the array down based on the space needed for the sub array
for (var j = arr.length + subArr.length - 2; j > i + subArr.length - 1; j--) {
arr[j] = arr[j - subArr.length + 1];
}
// Insert sub array elements where they belong
for (var k = 0; k < subArr.length; k++) {
arr[i + k] = subArr[k];
}
// Look at arr[i] again in case the first element in the subarray was another array;
i--;
}
}
}
flatten(x);
这里是 JSBin:http://jsbin.com/gazagemabe/edit?js,console
我想用递归来做这个,但我最终卡住了。我试图在不保留临时数组的情况下做到这一点,但事情似乎变得不正常了。我觉得我缺少递归的一些核心原则。
我意识到我需要一个基本案例。我能想到的唯一情况是当前处于展平状态的数组没有子数组。但是因为我总是通过引用传递数组,所以我没有什么可以 return.
我的伪代码是
function flatten(arr)
loop through arr
if arr[index] is an array
increase the array length arr[index] length
flatten(arr[index])
else
// unsure what to do here to modify the original array
这是一个完全就地工作的纯递归版本,不构建中间数组。
// Deep-flatten an array starting at index `i`.
function flatten(a, i = 0) {
if (i >= a.length)
// Null case--we are off the end of the array.
return;
var elt = a[i];
if (!Array.isArray(elt))
// Element is not an array. Proceed to next element.
i++;
else
// Element is an array.
// Unroll non-empty arrays; delete empty arrays.
if (elt.length) {
// Non-empty array.
// Unroll it into head and tail.
// Shift elements starting at `i` towards end of array.
// Have to do this recursively too--no loops!
(function shift(a, i, n = a.length) {
if (n > i ) a[n] = a[n-1], shift(a, i, --n);
}(a, i));
// Replace elt with its head, and place tail in slot we opened up.
a[i] = elt.shift();
a[i + 1] = elt;
}
else
// Array is empty.
// Delete the element and move remaining ones toward beginning of array.
// Again, have to do this recursively!
(function unshift(a, i) {
if (i < a.length) a[i] = a[i+1], unshift(a, ++i);
else a.length--;
}(a, i));
flatten(a, i);
}
var arr = [[[2, 3], 4], 5, [6, 7]];
flatten(arr);
console.log(arr);
[2, 3, 4, 5, 6, 7]
这个解决方案使用了ES6的点点滴滴,比如默认函数参数和Array.isArray
。如果您没有可用的 ES6,请相应地进行调整。
从内到外进行递归展平。首先对您找到的数组调用 flatten
函数,然后将该数组(现在是扁平的)的内容移动到父数组中。通过数组向后循环,这样您就不必为插入的项目调整循环变量。
如您所知,您插入的数组是平面的,您可以使用 splice
方法用其项目替换数组。
它是这样工作的:
start with
[[[2, 3], 4], 5, [6, 7]]
flatten [6,7] (which is already flat) and insert:
[[[2, 3], 4], 5, 6, 7]
flatten [[2, 3], 4] recursively calls flatten [2,3] and inserts in that array:
[[2, 3, 4], 5, 6, 7]
then it inserts [2, 3, 4]:
[2, 3, 4, 5, 6, 7]
代码:
function flatten(arr) {
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i].constructor === Array) {
flatten(arr[i]);
Array.prototype.splice.apply(arr, [i, 1].concat(arr[i]));
}
}
}
var x = [[[2, 3], 4], 5, [6, 7]];
flatten(x);
// Show result in snippet
document.write(JSON.stringify(x));