web-dev-qa-db-fra.com

Pourquoi pas Array.prototype.flatMap en javascript?

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?

54
Sergey Alaev

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]))
63
user633183

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)], [])

article de MDN sur flatMap

43
Kutyel

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.

9
Alan Mimms

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), [] )
5
Matthew Marichiba

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]));
1
JLRishe

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))
0
bigInt