Реверсивное выравнивание массивов Javascript
Я тренируюсь и пытаюсь написать рекурсивную функцию сглаживания массива. Код идет здесь:
function flatten() {
var flat = [];
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] instanceof Array) {
flat.push(flatten(arguments[i]));
}
flat.push(arguments[i]);
}
return flat;
}
Проблема в том, что если я передаю туда массив или вложенные массивы, я получаю ошибку "максимальный размер стека вызовов". Что я делаю неправильно?
Ответы
Ответ 1
Проблема в том, как вы передаете обработку массива, если это значение является массивом, тогда вы продолжаете называть его, вызывая бесконечный цикл
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;
}
Демо: Fiddle
Здесь более современная версия:
function flatten(items) {
const flat = [];
items.forEach(item => {
if (Array.isArray(item)) {
flat.push(...flatten(item));
} else {
flat.push(item);
}
});
return flat;
}
Ответ 2
Аскопельский подход...
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
В вашем коде отсутствует инструкция else, а рекурсивный вызов неверен (вы передаете один и тот же массив снова и снова, а не передаете его элементы).
Ваша функция может быть написана следующим образом:
function flatten() {
// variable number of arguments, each argument could be:
// - array
// array items are passed to flatten function as arguments and result is appended to flat array
// - anything else
// pushed to the flat array as-is
var flat = [],
i;
for (i = 0; i < arguments.length; i++) {
if (arguments[i] instanceof Array) {
flat = flat.concat(flatten.apply(null, arguments[i]));
} else {
flat.push(arguments[i]);
}
}
return flat;
}
// flatten([[[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]], [[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]]]);
// [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]
Ответ 4
Если кто-то ищет сгладить массив объектов (например, tree
), то вот код:
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))
Ответ 5
Если вы предполагаете, что ваш первый аргумент является массивом, вы можете сделать это довольно простым.
function flatten(a) {
return a.reduce((flat, i) => {
if (Array.isArray(i)) {
return flat.concat(flatten(i));
}
return flat.concat(i);
}, []);
}
Если вы хотите сгладить несколько массивов, просто сравните их перед прохождением.
Ответ 6
Если элемент является массивом, мы просто добавляем все остальные элементы в этот массив
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]]], []))
Ответ 7
[...arr.toString().split(",")]
Используйте метод toString()
в Object
. Используйте оператор распространения (...)
, чтобы создать массив строк и разделить его на ","
.
Пример:
let arr =[["1","2"],[[[3]]]]; // output : ["1", "2", "3"]
Ответ 8
Это решение Vanilla JavaScript для этой проблемы
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());
Ответ 9
Это должно работать
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;
}
Ответ 10
Другие ответы уже указывали на источник неисправности OP-кода. Написав более описательный код, проблема буквально сводится к "обнаружению массива /-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]
Ответ 11
Здесь рекурсивная реализация сокращения, взятая из абсурда, который имитирует 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);
}
В качестве входных данных может использоваться любое количество массивов или не массивов.
Источник: я автор абсурда
Ответ 12
Современный, но не кроссбраузерный
function flatten(arr) {
return arr.flatMap(el => {
if(Array.isArray(el)) {
return flatten(el)
} else {
return el;
}
})
}
Ответ 13
The clean way to flatten an Array in 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
Могу ли я использовать - 80% сент. 2019 г.
Ответ 14
вы должны добавить условие остановки для рекурсии.
в качестве примера
if len (arguments [i]) == 0 return