J'ai un tableau JavaScript comme:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Comment pourrais-je fusionner les tableaux internes distincts en un:
["$6", "$12", "$25", ...]
Vous pouvez utiliser concat
pour fusionner des tableaux:
var arrays = [
["$6"],
["$12"],
["$25"],
["$25"],
["$18"],
["$22"],
["$10"]
];
var merged = [].concat.apply([], arrays);
console.log(merged);
L'utilisation de la méthode apply
de concat
prendra simplement le deuxième paramètre sous forme de tableau, la dernière ligne est donc identique à celle-ci:
var merged2 = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);
Il existe également une méthode expérimentale Array.prototype.flat()
(ne faisant pas encore partie de la norme ECMAScript) que vous pouvez utiliser pour aplatir les tableaux, bien que elle ne soit pas encore disponible dans Edge ou Node.js .
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);
Voici une courte fonction qui utilise certaines des méthodes de tableau JavaScript les plus récentes pour aplatir un tableau à n dimensions.
function flatten(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
}
Usage:
flatten([[1, 2, 3], [4, 5]]); // [1, 2, 3, 4, 5]
flatten([[[1, [1.1]], 2, 3], [4, 5]]); // [1, 1.1, 2, 3, 4, 5]
Voici une solution fonctionnelle simple et performante:
var result = [].concat.apply([], [[1],[2,3],[4]]);
console.log(result); // [ 1, 2, 3, 4 ]
Pas de gâchis impératif.
Cela peut être mieux fait par la fonction de réduction javascript.
var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];
arrays = arrays.reduce(function(a, b){
return a.concat(b);
}, []);
Ou, avec ES2015:
arrays = arrays.reduce((a, b) => a.concat(b), []);
La plupart des réponses ne fonctionnent pas sur des tableaux énormes (par exemple 200 000 éléments) et même si elles le sont, elles sont lentes. La réponse de polkovnikov.ph a les meilleures performances, mais ne fonctionne pas pour un aplatissement en profondeur.
Voici la solution la plus rapide, qui fonctionne également sur les tableaux avec plusieurs niveaux d'imbrication
const flatten = function(arr, result = []) {
for (let i = 0, length = arr.length; i < length; i++) {
const value = arr[i];
if (Array.isArray(value)) {
flatten(value, result);
} else {
result.Push(value);
}
}
return result;
};
flatten(Array(200000).fill([1]));
Il gère très bien les tableaux énormes. Sur ma machine, ce code prend environ 14 ms à exécuter.
flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));
Cela fonctionne avec les tableaux imbriqués. Ce code produit [1, 1, 1, 1, 1, 1, 1, 1]
.
flatten([1, [1], [[1]]]);
Il n'a aucun problème avec les tableaux aplatissement comme celui-ci.
Update: il s'est avéré que cette solution ne fonctionnait pas avec les grands tableaux. Si vous cherchez une solution meilleure et plus rapide, consultez cette réponse .
function flatten(arr) {
return [].concat(...arr)
}
Is étend simplement arr
et le passe comme arguments à concat()
, qui fusionne tous les tableaux en un. C'est équivalent à [].concat.apply([], arr)
.
Vous pouvez également essayer ceci pour un aplatissement profond:
function deepFlatten(arr) {
return flatten( // return shalowly flattened array
arr.map(x=> // with each x in array
Array.isArray(x) // is x an array?
? deepFlatten(x) // if yes, return deeply flattened x
: x // if no, return just x
)
)
}
Voir la démo sur JSBin .
Références pour les éléments ECMAScript 6 utilisés dans cette réponse:
Remarque secondaire: les méthodes telles que find()
et les fonctions de flèche ne sont pas prises en charge par tous les navigateurs, mais cela ne signifie pas que vous ne pouvez pas utiliser ces fonctionnalités pour le moment. Il suffit d’utiliser Babel - pour transformer le code ES6 en ES5.
Vous pouvez utiliser Souligner :
var x = [[1], [2], [3, 4]];
_.flatten(x); // => [1, 2, 3, 4]
Les procédures génériques signifient que nous n'avons pas à réécrire la complexité à chaque fois que nous devons utiliser un comportement spécifique.
concatMap
(ou flatMap
) est exactement ce dont nous avons besoin dans cette situation.
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.map(f).reduce(concat, [])
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// your sample data
const data =
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
console.log (flatten (data))
Et oui, vous l’avez bien deviné, cela n’aplatit que un niveau, ce qui est exactement ce que cela donne {devrait} _
Imaginez un ensemble de données comme celui-ci
// Player :: (String, Number) -> Player
const Player = (name,number) =>
[ name, number ]
// team :: ( . Player) -> Team
const Team = (...players) =>
players
// Game :: (Team, Team) -> Game
const Game = (teamA, teamB) =>
[ teamA, teamB ]
// sample data
const teamA =
Team (Player ('bob', 5), Player ('alice', 6))
const teamB =
Team (Player ('ricky', 4), Player ('julian', 2))
const game =
Game (teamA, teamB)
console.log (game)
// [ [ [ 'bob', 5 ], [ 'alice', 6 ] ],
// [ [ 'ricky', 4 ], [ 'julian', 2 ] ] ]
Ok, disons maintenant que nous voulons imprimer une liste qui montre tous les joueurs qui participeront à game
…
const gamePlayers = game =>
flatten (game)
gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]
Si notre procédure flatten
aplatissait également les tableaux imbriqués, nous aboutirions à ce résultat inefficace…
const gamePlayers = game =>
badGenericFlatten(game)
gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]
Cela ne veut pas dire que, parfois, vous ne voulez pas non plus aplatir les tableaux imbriqués, mais seulement que cela ne devrait pas être le comportement par défaut.
Nous pouvons faire une procédure deepFlatten
avec facilité…
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.map(f).reduce(concat, [])
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// deepFlatten :: [[a]] -> [a]
const deepFlatten =
concatMap (x =>
Array.isArray (x) ? deepFlatten (x) : x)
// your sample data
const data =
[0, [1, [2, [3, [4, 5], 6]]], [7, [8]], 9]
console.log (flatten (data))
// [ 0, 1, [ 2, [ 3, [ 4, 5 ], 6 ] ], 7, [ 8 ], 9 ]
console.log (deepFlatten (data))
// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Là. Vous disposez maintenant d'un outil pour chaque travail: un pour supprimer un niveau d'imbrication, flatten
, et un pour effacer toutes les imbrications deepFlatten
.
Vous pouvez peut-être l'appeler obliterate
ou nuke
si vous n'aimez pas le nom deepFlatten
.
Ne pas itérer deux fois!
Bien sûr, les implémentations ci-dessus sont intelligentes et concises, mais utiliser un .map
suivi d'un appel à .reduce
signifie en réalité que nous faisons plus d'itérations que nécessaire.
L'utilisation d'un combinateur fiable que j'appelle mapReduce
aide à garder les itérations au minimum; il prend une fonction de mappage m :: a -> b
, une fonction de réduction r :: (b,a) ->b
et renvoie une nouvelle fonction de réduction - ce combinateur est au cœur de transducteurs; si cela vous intéresse, j'ai écrit d'autres réponses à leur sujet
// mapReduce = (a -> b, (b,a) -> b, (b,a) -> b)
const mapReduce = (m,r) =>
(acc,x) => r (acc, m (x))
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.reduce (mapReduce (f, concat), [])
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// deepFlatten :: [[a]] -> [a]
const deepFlatten =
concatMap (x =>
Array.isArray (x) ? deepFlatten (x) : x)
// your sample data
const data =
[ [ [ 1, 2 ],
[ 3, 4 ] ],
[ [ 5, 6 ],
[ 7, 8 ] ] ]
console.log (flatten (data))
// [ [ 1. 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]
console.log (deepFlatten (data))
// [ 1, 2, 3, 4, 5, 6, 7, 8 ]
Il existe une nouvelle méthode native ECMA 2018 appelée flat pour le faire exactement.
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]]
Une solution pour le cas plus général, lorsque vous pouvez avoir des éléments non-array dans votre tableau.
function flattenArrayOfArrays(a, r){
if(!r){ r = []}
for(var i=0; i<a.length; i++){
if(a[i].constructor == Array){
r.concat(flattenArrayOfArrays(a[i], r));
}else{
r.Push(a[i]);
}
}
return r;
}
Pour aplatir un tableau de tableaux à un seul élément, vous n'avez pas besoin d'importer de bibliothèque. Une simple boucle est à la fois la solution la plus simple et la plus efficace :
for (var i = 0; i < a.length; i++) {
a[i] = a[i][0];
}
Aux votants: lisez la question, ne cédez pas, cela ne convient pas à votre problème très différent. Cette solution est à la fois la plus rapide et la plus simple pour la question posée.
Qu'en est-il de l'utilisation de la méthode reduce(callback[, initialValue])
de JavaScript 1.8
list.reduce((p,n) => p.concat(n),[]);
Ferait le travail.
Une autre solution ECMAScript 6 de style fonctionnel:
Déclarez la fonction:
const flatten = arr => arr.reduce(
(a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
);
et l'utiliser:
flatten( [1, [2,3], [4,[5,[6]]]] ) // -> [1,2,3,4,5,6]
METTRE À JOUR:
Considérez également une fonction native Array.prototype.flat () (proposition pour ES6) disponible dans les dernières versions des navigateurs modernes.
_ {Merci à @ (Константин Ван) et @ (Mark Amery) l'ont mentionné dans les commentaires.} _
const common = arr.reduce((a, b) => [...a, ...b], [])
Remarque: Lorsque Function.prototype.apply
([].concat.apply([], arrays)
) ou l'opérateur spread ([].concat(...arrays)
) est utilisé afin d'aplatir un tableau, les deux peuvent provoquer des débordements de pile pour les grands tableaux, car chaque argument d'une fonction est stocké dans la pile.
Voici une implémentation sécurisée de la pile, dans un style fonctionnel, qui met en balance les exigences les plus importantes:
// small, reusable auxiliary functions:
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc); // aka reduce
const uncurry = f => (a, b) => f(a) (b);
const concat = xs => y => xs.concat(y);
// the actual function to flatten an array - a self-explanatory one-line:
const flatten = xs => foldl(concat) ([]) (xs);
// arbitrary array sizes (until the heap blows up :D)
const xs = [[1,2,3],[4,5,6],[7,8,9]];
console.log(flatten(xs));
// Deriving a recursive solution for deeply nested arrays is trivially now
// yet more small, reusable auxiliary functions:
const map = f => xs => xs.map(apply(f));
const apply = f => a => f(a);
const isArray = Array.isArray;
// the derived recursive function:
const flattenr = xs => flatten(map(x => isArray(x) ? flattenr(x) : x) (xs));
const ys = [1,[2,[3,[4,[5],6,],7],8],9];
console.log(flattenr(ys));
Dès que vous vous habituez aux petites fonctions fléchées sous forme curry, composition de fonctions et fonctions d'ordre supérieur, ce code se lit comme une prose. La programmation consiste alors simplement à assembler de petits blocs de construction qui fonctionnent toujours comme prévu, car ils ne contiennent aucun effet secondaire.
Voir lodash aplati , soulignement aplati (peu profonde true
)
function flatten(arr) {
return arr.reduce((acc, e) => acc.concat(e), []);
}
function flatten(arr) {
return [].concat.apply([], arr);
}
Testé avec
test('already flatted', () => {
expect(flatten([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});
test('flats first level', () => {
expect(flatten([1, [2, [3, [4]], 5]])).toEqual([1, 2, [3, [4]], 5]);
});
Voir lodash flattenDeep , soulignement flatten
function flattenDeep(arr) {
return arr.reduce((acc, e) => Array.isArray(e) ? acc.concat(flattenDeep(e)) : acc.concat(e), []);
}
Testé avec
test('already flatted', () => {
expect(flattenDeep([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});
test('flats', () => {
expect(flattenDeep([1, [2, [3, [4]], 5]])).toEqual([1, 2, 3, 4, 5]);
});
Si vous avez seulement des tableaux avec 1 élément string:
[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');
va faire le travail. Bt qui correspond spécifiquement à votre exemple de code.
Façon ES6:
const flatten = arr => arr.reduce((acc, next) => acc.concat(Array.isArray(next) ? flatten(next) : next), [])
const a = [1, [2, [3, [4, [5]]]]]
console.log(flatten(a))
Chemin ES5 pour la fonction flatten
avec ES3 fallback pour les tableaux imbriqués N-times:
var flatten = (function() {
if (!!Array.prototype.reduce && !!Array.isArray) {
return function(array) {
return array.reduce(function(prev, next) {
return prev.concat(Array.isArray(next) ? flatten(next) : next);
}, []);
};
} else {
return function(array) {
var arr = [];
var i = 0;
var len = array.length;
var target;
for (; i < len; i++) {
target = array[i];
arr = arr.concat(
(Object.prototype.toString.call(target) === '[object Array]') ? flatten(target) : target
);
}
return arr;
};
}
}());
var a = [1, [2, [3, [4, [5]]]]];
console.log(flatten(a));
var arrays = [["a"], ["b", "c"]];
Array.prototype.concat.apply([], arrays);
// gives ["a", "b", "c"]
(J'écris ceci simplement comme réponse séparée, basée sur le commentaire de @danhbear.)
Je préférerais transformer tout le tableau, tel quel, en une chaîne, mais contrairement à d'autres réponses, je le ferais à l'aide de JSON.stringify
sans utiliser la méthode toString()
, qui produit un résultat non souhaité.
Avec cette sortie JSON.stringify
, tout ce qui reste à faire est de supprimer tous les crochets, d’envelopper encore le résultat avec des crochets de début et de fin, et de servir le résultat avec JSON.parse
, ce qui ramène la chaîne à "vie".
var arr = ["abc",[[[6]]],["3,4"],"2"];
var s = "[" + JSON.stringify(arr).replace(/\[|]/g,'') +"]";
var flattened = JSON.parse(s);
console.log(flattened)
Une approche haaskellesque
function flatArray([x,...xs]){
return x ? [...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);
L’autre jour, j’étais en train de jouer avec ES6 Generators et j’ai écrit this Gist . Qui contient...
function flatten(arrayOfArrays=[]){
function* flatgen() {
for( let item of arrayOfArrays ) {
if ( Array.isArray( item )) {
yield* flatten(item)
} else {
yield item
}
}
}
return [...flatgen()];
}
var flatArray = flatten([[1, [4]],[2],[3]]);
console.log(flatArray);
Fondamentalement, je crée un générateur qui boucle sur le tableau d'entrée d'origine. S'il trouve un tableau, il utilise l'opérateur yield * en combinaison avec la récursivité pour aplatir en permanence les tableaux internes. Si l'élément n'est pas un tableau, il ne fait que renvoyer l'élément unique. Puis, à l’aide de l’opérateur ES6 Spread (également appelé opérateur Splat), j’aplanis le générateur en une nouvelle instance de tableau.
Je n’ai pas testé les performances de ce logiciel, mais j’imagine que c’est un bon exemple simple d'utilisation des générateurs et de l'opérateur de rendement *.
Mais encore une fois, j'étais en train de gaffer, alors je suis sûr qu'il existe des moyens plus performants de le faire.
Je l'ai fait en utilisant la récursivité et les fermetures
function flatten(arr) {
var temp = [];
function recursiveFlatten(arr) {
for(var i = 0; i < arr.length; i++) {
if(Array.isArray(arr[i])) {
recursiveFlatten(arr[i]);
} else {
temp.Push(arr[i]);
}
}
}
recursiveFlatten(arr);
return temp;
}
juste la meilleure solution sans lodash
let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))
Je recommande une fonction génératrice peu encombrante :
function* flatten(arr) {
if (!Array.isArray(arr)) yield arr;
else for (let el of arr) yield* flatten(el);
}
// Example:
console.log(...flatten([1,[2,[3,[4]]]])); // 1 2 3 4
Si vous le souhaitez, créez un tableau de valeurs aplaties comme suit:
let flattened = [...flatten([1,[2,[3,[4]]]])]; // [1, 2, 3, 4]
On dirait que cela ressemble à un travail pour RECURSION!
Code:
var flatten = function(toFlatten) {
var isArray = Object.prototype.toString.call(toFlatten) === '[object Array]';
if (isArray && toFlatten.length > 0) {
var head = toFlatten[0];
var tail = toFlatten.slice(1);
return flatten(head).concat(flatten(tail));
} else {
return [].concat(toFlatten);
}
};
Utilisation:
flatten([1,[2,3],4,[[5,6],7]]);
// Result: [1, 2, 3, 4, 5, 6, 7]
Ce n'est pas difficile, il suffit de parcourir les tableaux et de les fusionner:
var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];
for (var i = 0; i < input.length; ++i) {
result = result.concat(input[i]);
}
La logique ici est de convertir le tableau d'entrée en chaîne et de supprimer tous les crochets ([]) et d'analyser la sortie dans un tableau. J'utilise la fonctionnalité de modèle ES6 pour cela.
var x=[1, 2, [3, 4, [5, 6,[7], 9],12, [12, 14]]];
var y=JSON.parse(`[${JSON.stringify(x).replace(/\[|]/g,'')}]`);
console.log(y)
De nos jours, le meilleur moyen de procéder consiste à joindre et à diviser le tableau de cette manière.
var multipleArrays = [["$6","$Demo"], ["$12",["Multi","Deep"]], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]]
var flattened = multipleArrays.join().split(",")
Cette solution fonctionne avec plusieurs niveaux et est également une solution unique.
EDIT pour ECMAScript 6
Comme ECMAScript 6 a été normalisé, vous pouvez modifier l'opération [].concat.apply([], arrays);
pour [].concat(...arrays);
.
var flattened = [].concat(...input);
EDIT La solution la plus efficace
Le moyen le plus efficace de résoudre le problème consiste à utiliser une boucle. Vous pouvez comparer la vitesse "ops/sec" ici
var flattened=[];
for (var i=0; i<input.length; ++i) {
var current = input[i];
for (var j=0; j<current.length; ++j)
flattened.Push(current[j]);
}
J'espère que ça aide
const flatten = array => array.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
Par demande, casser la ligne est fondamentalement avoir cela.
function flatten(array) {
// reduce traverses the array and we return the result
return array.reduce(function(acc, b) {
// if is an array we use recursion to perform the same operations over the array we found
// else we just concat the element to the accumulator
return acc.concat( Array.isArray(b) ? flatten(b) : b);
}, []); // we initialize the accumulator on an empty array to collect all the elements
}
Je propose deux solutions courtes sans récursivité. Ils ne sont pas optimaux du point de vue de la complexité informatique, mais fonctionnent bien dans les cas moyens:
let a = [1, [2, 3], [[4], 5, 6], 7, 8, [9, [[10]]]];
// Solution #1
while (a.find(x => Array.isArray(x)))
a = a.reduce((x, y) => x.concat(y), []);
// Solution #2
let i = a.findIndex(x => Array.isArray(x));
while (i > -1)
{
a.splice(i, 1, ...a[i]);
i = a.findIndex(x => Array.isArray(x));
}
Je suis conscient que c'est hacky, mais la façon la plus succincte d'aplatir un tableau (de n'importe quelle profondeur!) De chaînes (sans virgule!) Consiste à transformer le tableau en chaîne, puis de scinder la chaîne en virgules:
var myArray =[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];
var myFlatArray = myArray.toString().split(',');
myFlatArray;
// ["$6", "$12", "$25", "$25", "$18", "$22", "$10", "$0", "$15", "$3", "$75", "$5", "$100", "$7", "$3", "$75", "$5"]
Cela devrait fonctionner sur n'importe quelle profondeur de tableaux imbriqués ne contenant que des chaînes et des nombres (nombres entiers et flottants), avec l'avertissement que les nombres seront convertis en chaînes dans le processus. Ceci peut être résolu avec un peu de mapping:
var myArray =[[[1,2],[3,4]],[[5,6],[7,8]],[[9,0]]];
var myFlatArray = myArray.toString().split(',').map(function(e) { return parseInt(e); });
myFlatArray;
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
si votre tableau est constitué uniquement d'entiers ou de chaînes, vous pouvez utiliser ce hack:
var arr = [345,2,[34],2,[524,[5456]],[5456]];
var flat = arr.toString().split(',');
Works, en FF, IE et Chrome n'ont pas encore testé les autres navigateurs.
Pour aplatir un tableau à deux dimensions sur une ligne:
[[1, 2], [3, 4, 5]].reduce(Function.prototype.apply.bind(Array.prototype.concat))
// => [ 1, 2, 3, 4, 5 ]
Voici un autre profond aplatir pour les navigateurs modernes:
function flatten(xs) {
xs = Array.prototype.concat.apply([], xs);
return xs.some(Array.isArray) ? flatten(xs) : xs;
};
Voici une version en TypeScript basée sur la réponse de artif3x, avec une implémentation supplémentaire de flatMap
pour les fans de Scala.
function flatten<T>(items: T[][]): T[] {
return items.reduce((prev, next) => prev.concat(next), []);
}
function flatMap<T, U>(items: T[], f: (t: T) => U[]): U[] {
return items.reduce((prev, next) => prev.concat(f(next)), new Array<U>());
}
Il est préférable de le faire de manière récursive, donc si encore un autre tableau à l'intérieur de l'autre tableau peut être filtré ...
const flattenArray = arr =>
arr.reduce(
(res, cur) =>
!Array.isArray(cur)
? res.concat(cur)
: res.concat(flattenArray(cur)), []);
Et vous pouvez l'appeler comme ceci:
flattenArray([[["Alireza"], "Dezfoolian"], ["is a"], ["developer"], [[1, [2, 3]]]]);
et le résultat ci-dessous:
["Alireza", "Dezfoolian", "is a", "developer", 1, 2, 3]
Juste pour ajouter aux bonnes solutions. J'ai utilisé la récursivité pour résoudre ce problème.
const flattenArray = () => {
let result = [];
return function flat(arr) {
for (let i = 0; i < arr.length; i++) {
if (!Array.isArray(arr[i])) {
result.Push(arr[i]);
} else {
flat(arr[i])
}
}
return result;
}
}
Résultats du test: https://codepen.io/ashermike/pen/mKZrWK
Le code suivant va aplatir les tableaux profondément imbriqués:
/**
* [Function to flatten deeply nested array]
* @param {[type]} arr [The array to be flattened]
* @param {[type]} flattenedArr [The flattened array]
* @return {[type]} [The flattened array]
*/
function flattenDeepArray(arr, flattenedArr) {
let length = arr.length;
for(let i = 0; i < length; i++) {
if(Array.isArray(arr[i])) {
flattenDeepArray(arr[i], flattenedArr);
} else {
flattenedArr.Push(arr[i]);
}
}
return flattenedArr;
}
let arr = [1, 2, [3, 4, 5], [6, 7]];
console.log(arr, '=>', flattenDeepArray(arr, [])); // [ 1, 2, [ 3, 4, 5 ], [ 6, 7 ] ] '=>' [ 1, 2, 3, 4, 5, 6, 7 ]
arr = [1, 2, [3, 4], [5, 6, [7, 8, [9, 10]]]];
console.log(arr, '=>', flattenDeepArray(arr, [])); // [ 1, 2, [ 3, 4 ], [ 5, 6, [ 7, 8, [Object] ] ] ] '=>' [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
Je réponds à cette question simplement avec ES6
, en supposant que le tableau en profondeur est:
const deepArray = ['1',[['a'],['b']],[2],[[[['4',[3,'c']]]],[5]]];
Si vous savez ou devinez que la profondeur de vos tableaux ne dépasse pas un nombre tel que 7
, utilisez le code ci-dessous:
const flatArray = deepArray.flat(7);
Mais si vous ne connaissez pas la profondeur de vos tableaux profonds ou si votre moteur JavaScript
ne supporte pas flat
comme react-native
JavaScriptCore
, utilisez la fonction ci-dessous qui est utilisée JavaScript
reduce
:
const deepFlatten = arr =>
arr.reduce(
(acc, val) =>
Array.isArray(val)
? acc.concat(deepFlatten(val))
: acc.concat(val),
[]
);
Les deux méthodes retournent en dessous du résultat:
["1", "a", "b", 2, "4", 3, "c", 5]
Vous pouvez utiliser Ramda JSaplatir
var arr = [[1,2], [3], [4,5]];
var flattenedArray = R.flatten(arr);
console.log(flattenedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
Vous pouvez aplatir un tableau de tableaux à l'aide de Array.prototype.reduce()
et Array.prototype.concat()
.
var data = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]].reduce(function(a, b) {
return a.concat(b);
}, []);
console.log(data);
Documents associés: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/concat
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Vous pouvez utiliser Array.flat()
avec Infinity
pour n’importe quelle profondeur de tableau imbriqué.
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)
vérifier ici pour navigateur compatibilité
let arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];
arr = arr.reduce((a, b) => a.concat(b)); // flattened
si vous utilisez lodash, vous pouvez simplement utiliser sa méthode flatten
: https://lodash.com/docs/4.17.14#flatten
La bonne chose à propos de lodash est qu’il dispose également de méthodes pour aplatir les tableaux:
i) récursivement: https://lodash.com/docs/4.17.14#flattenDeep
ii) Jusqu'à n niveaux d'imbrication: https://lodash.com/docs/4.17.14#flattenDepth
Par exemple
const _ = require("lodash");
const pancake = _.flatten(array)
Simple flatten util je l'ai écrit
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 ]
À l'origine, je pensais utiliser la méthode .reduce
et appeler de manière récursive une fonction pour aplatir les tableaux internes. Toutefois, cela peut entraîner des débordements de pile lorsque vous utilisez un tableau profondément imbriqué de tableaux profondément imbriqués. L'utilisation de concat n'est pas non plus la meilleure solution car chaque itération créera une nouvelle copie superficielle du tableau. Ce que nous pouvons faire à la place est la suivante:
const flatten = arr => {
for(let i = 0; i < arr.length;) {
const val = arr[i];
if(Array.isArray(val)) {
arr.splice(i, 1, ...val);
} else {
i ++;
}
}
return arr;
}
Nous ne créons pas de nouveaux tableaux via concat et nous n'appelons aucune fonction de manière récursive.
Version récursive qui fonctionne sur tous les types de données
/*jshint esversion: 6 */
// nested array for testing
let nestedArray = ["firstlevel", 32, "alsofirst", ["secondlevel", 456,"thirdlevel", ["theinnerinner", 345, {firstName: "Donald", lastName: "Duck"}, "lastinner"]]];
// wrapper function to protect inner variable tempArray from global scope;
function flattenArray(arr) {
let tempArray = [];
function flatten(arr) {
arr.forEach(function(element) {
Array.isArray(element) ? flatten(element) : tempArray.Push(element); // ternary check that calls flatten() again if element is an array, hereby making flatten() recursive.
});
}
// calling the inner flatten function, and then returning the temporary array
flatten(arr);
return tempArray;
}
// example usage:
let flatArray = flattenArray(nestedArray);
Définissez un tableau de tableaux en javascript appelé foo et aplatissez ce tableau de tableaux en un seul tableau en utilisant la méthode intégrée concat de tableau de javascript:
const foo = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
console.log({foo});
const bar = [].concat(...foo)
console.log({bar});
Devrait imprimer:
{ foo:
[ [ '$6' ],
[ '$12' ],
[ '$25' ],
[ '$25' ],
[ '$18' ],
[ '$22' ],
[ '$10' ] ] }
{ bar: [ '$6', '$12', '$25', '$25', '$18', '$22', '$10' ] }
Pouvez-vous essayer ceci:
[].concat.apply([], myArray);
Array.prototype.flatten = Array.prototype.flatten || function() {
return [].reduce.call(this, function(flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? toFlatten.flatten() : toFlatten);
},[])
};
Si vous devez prendre en charge IE8 et ne pouvez donc pas utiliser de méthodes telles que reduction ou isArray, voici une solution possible. C'est une approche verbeuse pour vous aider à comprendre l'algorithme récursif.
function flattenArray(a){
var aFinal = [];
(function recursiveArray(a){
var i,
iCount = a.length;
if (Object.prototype.toString.call(a) === '[object Array]') {
for (i = 0; i < iCount; i += 1){
recursiveArray(a[i]);
}
} else {
aFinal.Push(a);
}
})(a);
return aFinal;
}
var aMyArray = [6,3,4,[12,14,15,[23,24,25,[34,35],27,28],56],3,4];
var result = flattenArray(aMyArray);
console.log(result);
J'ai une solution simple sans utiliser dans une fonction spéciale js. (comme réduire etc)
const input = [[0, 1], [2, 3], [4, 5]]
let flattened=[];
for (let i=0; i<input.length; ++i) {
let current = input[i];
for (let j=0; j<current.length; ++j)
flattened.Push(current[j]);
}
// using Es6 flat()
let arr = [1,[2,[3,[4,[5,[6,7],8],9],10]]]
console.log(arr.flat(Infinity))
// using Es6 reduce()
let flatIt = (array) => array.reduce(
(x, y) => x.concat(Array.isArray(y) ? flatIt(y) : y), []
)
console.log(flatIt(arr))
// using recursion
function myFlat(array) {
let flat = [].concat(...array);
return flat.some(Array.isArray) ? myFlat(flat) : flat;
}
console.log(myFlat(arr));
// using string manipulation
let strArr = arr.toString().split(',');
for(let i=0;i<strArr.length;i++)
strArr[i]=parseInt(strArr[i]);
console.log(strArr)
Beaucoup plus simple et simple; avec option pour aplatir profondément;
const flatReduce = (arr, deep) => {
return arr.reduce((acc, cur) => {
return acc.concat(Array.isArray(cur) && deep ? flatReduce(cur, deep) : cur);
}, []);
};
console.log(flatReduce([1, 2, [3], [4, [5]]], false)); // => 1,2,3,4,[5]
console.log(flatReduce([1, 2, [3], [4, [5, [6, 7, 8]]]], true)); // => 1,2,3,4,5,6,7,8
[23, [34, 454], 12, 34].flatten();
// --> [23,34, 454, 12, 34]
[23, [34, 454,[66,55]], 12, 34].flatten();
// --> [23, 34, 454, [66,55], 12, 34]
[23, [34, 454,[66,55]], 12, 34].flatten(true);
// --> [23, 34, 454, 66, 55, 12, 34]
Si tous les éléments du tableau sont Integer, Float, ... ou/et String, procédez comme suit:
var myarr=[1,[7,[9.2]],[3],90];
eval('myarr=['+myarr.toString()+']');
print(myarr);
// [1, 7, 9.2, 3, 90]
PourScala
les utilisateurs recherchant un moyen de répliquerSeq.flatten
en Javascript, voici un proxénète de Array
:
Array.prototype.flatten = function() {
return [].concat.apply([], this);
};
qui peut être utilisé de cette façon:
[[12, 3, 5], [1], [], [3, 4]].flatten() // [12, 3, 5, 1, 3, 4]
var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];
var merged = [].concat.apply([], arrays);
alert(merged);
Voici ma version de celui-ci. Il vous permet d’aplatir un objet compliqué qui pourrait être utilisé dans plusieurs scénarios:
Contribution
var input = {
a: 'asdf',
b: [1,2,3],
c: [[1,2],[3,4]],
d: {subA: [1,2]}
}
Code
La fonction est comme ça:
function flatten (input, output) {
if (isArray(input)) {
for(var index = 0, length = input.length; index < length; index++){
flatten(input[index], output);
}
}
else if (isObject(input)) {
for(var item in input){
if(input.hasOwnProperty(item)){
flatten(input[item], output);
}
}
}
else {
return output.Push(input);
}
};
function isArray(obj) {
return Array.isArray(obj) || obj.toString() === '[object Array]';
}
function isObject(obj) {
return obj === Object(obj);
}
Utilisation
var output = []
flatten(input, output);
Sortie
["asdf", 1, 2, 3, 1, 2, 3, 4, 1, 2]
Pure magie de l'es6
const flat = A => A.reduce((A, a) => Array.isArray(a) ? [...A, ...flat(a)] : [...A, a], []);
essayez cette méthode,
arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
concat_arr = arr.concat.apply([], arr)
console.log(concat_arr)
const flattenArray = myArray => (myArray.toString().split(','));
console.log(flattenArray([["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]));
utilisez arrays.flat ();
var arrays = [
["$6"],
["$12"],
["$25"],
["$25"],
["$18"],
["$22"],
["$10"]
];
arrays.flat();
Pour ce faire, il existe un moyen beaucoup plus rapide que d’utiliser la méthode merge.concat.apply () indiquée dans la première réponse, et je veux dire plus vite que plus de plusieurs ordres de grandeur plus rapidement. Cela suppose que votre environnement a accès aux méthodes Array ES5.
var array2d = [
["foo", "bar"],
["baz", "biz"]
];
merged = array2d.reduce(function(prev, next) {
return prev.concat(next);
});
Voici le lien jsperf: http://jsperf.com/2-dimensional-array-merge
// 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. 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
Je n'ai pas trouvé ici de solution pour les grands réseaux lorsque l'aplatissement n'est pas profond. Donc, ma version:
function flatten(arr){
result = []
for (e of arr)
result.Push(...e)
return result
}
/**
* flatten an array first level
* @method flatten
* @param array {Array}
* @return {Array} flatten array
*/
function flatten(array) {
return array.reduce((acc, current) => acc.concat(current), []);
}
/**
* flatten an array recursively
* @method flattenDeep
* @param array {Array}
* @return {Array} flatten array
*/
function flattenDeep(array) {
return array.reduce((acc, current) => {
return Array.isArray(current) ? acc.concat(flattenDeep(current)) : acc.concat([current]);
}, []);
}
/**
* flatten an array recursively limited by depth
* @method flattenDepth
* @param array {Array}
* @return {Array} flatten array
*/
function flattenDepth(array, depth) {
if (depth === 0) {
return array;
}
return array.reduce((acc, current) => {
return Array.isArray(current) ? acc.concat(flattenDepth(current, --depth)) : acc.concat([current]);
}, []);
}
[1,[2,3],[4,[5,6]]].reduce(function(p, c) {
return p.concat(c instanceof Array ?
c.reduce(arguments.callee, []) :
[c]);
}, []);