Je fais de l'exercice et j'essaie d'écrire une fonction d'aplatissement de tableau récursif. Le code va ici:
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;
}
Le problème est que si j'y passe un tableau ou des tableaux imbriqués, l'erreur "Taille maximale de la pile d'appels dépassée". Qu'est-ce que je fais mal?
Le problème est de savoir comment vous passez le traitement du tableau. Si la valeur est un tableau, vous continuez à l’appeler, ce qui provoque une boucle infinie.
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;
}
Démo: Fiddle
Voici une version plus moderne:
function flatten(items) {
const flat = [];
items.forEach(item => {
if (Array.isArray(item)) {
flat.Push(...flatten(item));
} else {
flat.Push(item);
}
});
return flat;
}
Une approche haaskellesque ...
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);
Si l'élément est un tableau, nous ajoutons simplement tous les éléments restants à ce tableau
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]]], []))
Si vous supposez que votre premier argument est un tableau, vous pouvez simplifier les choses.
function flatten(a) {
return a.reduce((flat, i) => {
if (Array.isArray(i)) {
return flat.concat(flatten(i));
}
return flat.concat(i);
}, []);
}
Si vous voulez aplatir plusieurs tableaux, il suffit de les concaténer avant de les passer.
Votre code manque une instruction else et l'appel récursif est incorrect (vous passez le même tableau encore et encore au lieu de lui transmettre ses éléments).
Votre fonction pourrait être écrite comme ceci:
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]
Si quelqu'un cherche un tableau aplati d'objets (par exemple, tree
), voici un code:
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))
Les autres réponses indiquaient déjà la source du dysfonctionnement du code du PO. En écrivant un code plus descriptif, le problème se résume littéralement à une "détection de matrice/-reduce/-concat-récursivité" ...
(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));
emprunter du code à l’une des autres réponses comme preuve de concept ...
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]
Cela devrait marcher
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;
}
Ceci est une solution JavaScript Vanille à ce problème
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());