flatMap
est incroyablement utile sur les collections, mais javascript n'en fournit pas alors que Array.prototype.map
. Pourquoi?
Est-il possible d'émuler flatMap
en javascript de manière simple et efficace sans définir flatMap
manuellement?
Mise à jour: Array.prototype.flatMap
est sur le chemin de la version native d’ECMAScript. Il est actuellement dans Stage 4.
Il est largement pris en charge dans de nombreux environnements. Voir si cela fonctionne dans votre navigateur en utilisant cet extrait ci-dessous -
const data =
[ 1, 2, 3, 4 ]
console.log(data.flatMap(x => Array(x).fill(x)))
// [ 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 ]
Pourquoi pas Array.prototype.flatMap en javascript?
Parce que la programmation n'est pas magique et que chaque langue n'a pas de caractéristiques/primitives que toutes les autres langues ont
Ce qui compte, c'est
JavaScript vous donne la possibilité de le définir vous-même
const concat = (x,y) =>
x.concat(y)
const flatMap = (f,xs) =>
xs.map(f).reduce(concat, [])
const xs = [1,2,3]
console.log(flatMap(x => [x-1, x, x+1], xs))
Ou une réécriture qui réduit les deux boucles en une seule
const flatMap = (f,xs) =>
xs.reduce((acc,x) =>
acc.concat(f(x)), [])
const xs = [1,2,3]
console.log(flatMap(x => [x-1, x, x+1], xs))
Si vous le voulez sur le Array.prototype
, rien ne t'arrête
const concat = (x,y) =>
x.concat(y)
const flatMap = (f,xs) =>
xs.map(f).reduce(concat, [])
Array.prototype.flatMap = function(f) {
return flatMap(f,this)
}
const xs = [1,2,3]
console.log(xs.flatMap(x => [x-1, x, x+1]))
flatMap
a été approuvé par le TC39 dans le cadre de ES2019 (ES10). Vous pouvez l'utiliser comme ceci:
[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
Voici ma propre implémentation de la méthode:
const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])
Je sais que vous avez dit que vous ne vouliez pas le définir vous-même, mais cette implémentation est une définition assez triviale.
Il y a aussi ceci de la même page github:
Voici un moyen plus court d’utiliser es6 spread, comme pour renaudtertrais - mais en utilisant es6 sans ajouter de valeur au prototype.
var flatMap = (a, cb) => [].concat(...a.map(cb))
const s = (v) => v.split(',')
const arr = ['cat,dog', 'fish,bird']
flatMap(arr, s)
Est-ce que l'un ou l'autre aiderait?
Il convient de noter (grâce à @ftor) que cette dernière "solution" souffre de "Taille maximale de la pile d'appels dépassée" si elle est appelée sur un tableau très volumineux (par exemple 300 000 éléments) a
.
Lodash fournit une fonction flatmap qui, pour moi, est pratiquement équivalente à celle fournie par Javascript. Si vous n'êtes pas un utilisateur de Lodash, alors la méthode Array.reduce()
d'ES6 peut vous donner le même résultat, mais vous devez mapper puis aplatir par étapes discrètes.
Vous trouverez ci-dessous un exemple de chaque méthode, mappant une liste d’entiers et ne renvoyant que les probabilités.
Lodash:
_.flatMap([1,2,3,4,5], i => i%2 !== 0 ? [i] : [])
ES6 Réduire:
[1,2,3,4,5].map(i => i%2 !== 0 ? [i] : []).reduce( (a,b) => a.concat(b), [] )
Une approche assez concise consiste à utiliser le Array#concat.apply
:
const flatMap = (arr, f) => [].concat.apply([], arr.map(f))
console.log(flatMap([1, 2, 3], el => [el, el * el]));
Nous avons maintenant une flatMap()
en Javascript! Et il est supporté assez bien
La méthode flatMap () mappe d'abord chaque élément à l'aide d'une fonction de mappage, puis aplatit le résultat dans un nouveau tableau. Il est identique à une carte () suivie d'un plat () de profondeur 1
const dublicate = x => [x, x];
console.log([1, 2, 3].flatMap(dublicate))