Vraag Waarom geen Array.prototype.flatMap in javascript?


flatMap is ongelooflijk nuttig in collecties, maar javascript biedt dit niet zolang Array.prototype.map. Waarom?

Is er een manier om te emuleren flatMap in javascript op zowel eenvoudige als efficiënte manier zonder definitie flatMap handmatig?


26
2017-10-03 18:00


oorsprong


antwoorden:


Waarom geen Array.prototype.flatMap in javascript?

Omdat programmeren geen magie is en elke taal geen kenmerken / primitieven heeft die elke andere taal heeft

Waar het om gaat is

JavaScript geeft je de mogelijkheid om het zelf te definiëren

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

Of een herschrijf dat de twee loops ineen klapt

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

Als je het op de Array.prototype, niets houdt je tegen

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

Bijwerken: Array.prototype.flatMap is op weg naar native ECMAScript. Het bevindt zich momenteel in fase-3.


27
2017-10-03 18:46



Ik denk dat dit een goed moment is om dat aan te kondigen flatMap is geweest voorgestelde naar de TC39 

En geef ook mijn implementatie van de methode (meer 2017-achtig;)

const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])

Genieten!

BEWERK: Eigenlijk weet rechts het fase-3 dus het is zeer waarschijnlijk dat het de volgende ES-release bereikt 🏼


16
2017-11-29 09:44



Ik weet dat je zei dat je het niet zelf wilde definiëren, maar deze implementatie is een vrij triviale definitie.

Er is ook dit van dezelfde github-pagina:

Hier is een stukje kortere weg met behulp van es6 spread, vergelijkbaar met renaudtertrais's - maar met es6 en niet toegevoegd aan het prototype.

var flatMap = (a, cb) => [].concat(...a.map(cb))

const s = (v) => v.split(',')
const arr = ['cat,dog', 'fish,bird']

flatMap(arr, s)

Zou een van deze helpen?

Opgemerkt moet worden (dankzij @ftor) dat deze laatste "oplossing" lijdt onder "Maximale grootte van de oproepstapel overschreden" indien aangeroepen op een werkelijk grote (bijv. 300k elementen) rij a.


10
2017-10-03 18:10



Lodash biedt een flatmap-functie, die voor mij vrijwel gelijk is aan Javascript die deze native levert. Als je geen Lodash-gebruiker bent, dan ES6's Array.reduce() methode kan hetzelfde resultaat geven, maar je moet toewijzen en vervolgens afvlakken in discrete stappen.

Hieronder ziet u een voorbeeld van elke methode, waarbij u een lijst met gehele getallen toewijst en alleen de kansen retourneert.

Lodash:

_.flatMap([1,2,3,4,5], i => i%2 !== 0 ? [i] : [])

ES6 Verkleinen:

[1,2,3,4,5].map(i => i%2 !== 0 ? [i] : []).reduce( (a,b) => a.concat(b), [] )

5
2017-10-13 20:53



Een vrij beknopte benadering is om gebruik te maken van de Array#concat.apply:

const flatMap = (arr, f) => [].concat.apply([], arr.map(f))

console.log(flatMap([1, 2, 3], el => [el, el * el]));


1
2017-11-14 18:07



Ik deed zoiets als dit:

Array.prototype.flatMap = function(selector){ 
  return this.reduce((prev, next) => 
    (/*first*/ selector(prev) || /*all after first*/ prev).concat(selector(next))) 
}

[[1,2,3],[4,5,6],[7,8,9]].flatMap(i => i); //[1, 2, 3, 4, 5, 6, 7, 8, 9]

[{subarr:[1,2,3]},{subarr:[4,5,6]},{subarr:[7,8,9]}].flatMap(i => i.subarr); //[1, 2, 3, 4, 5, 6, 7, 8, 9]


0
2017-07-31 07:58