admin管理员组文章数量:1134238
flatMap
is incredibly useful on collections, but javascript does not provide one while having Array.prototype.map
. Why?
Is there any way to emulate flatMap
in javascript in both easy and efficient way w/o defining flatMap
manually?
flatMap
is incredibly useful on collections, but javascript does not provide one while having Array.prototype.map
. Why?
Is there any way to emulate flatMap
in javascript in both easy and efficient way w/o defining flatMap
manually?
8 Answers
Reset to default 119Update: Array.prototype.flatMap
made it into ES2019
It is widely supported in many environments. See if it works in your browser using this snippet below -
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 ]
"Why no Array.prototype.flatMap in javascript?"
Because programming isn't magic and every language doesn't have features/primitives that every other language has. What matters is JavaScript gives you the ability to define it on your own -
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))
Or a rewrite that collapses the two loops into one -
const flatMap = (f, xs) =>
xs.reduce((r, x) => r.concat(f(x)), [])
const xs = [1,2,3]
console.log(flatMap(x => [x-1, x, x+1], xs))
If you want it to extend the Array.prototype
, nothing is stopping you -
if (!Array.prototype.flatMap) {
function flatMap (f, ctx) {
return this.reduce
( (r, x, i, a) =>
r.concat(f.call(ctx, x, i, a))
, []
)
}
Array.prototype.flatMap = flatMap
}
const ranks =
[ 'J', 'Q', 'K', 'A' ]
const suits =
[ '♡', '♢', '♤', '♧' ]
const result =
ranks.flatMap(r =>
suits.flatMap(s =>
[[r, s]]
)
)
console.log(JSON.stringify(result))
// [ ['J','♡'], ['J','♢'], ['J','♤'], ['J','♧']
// , ['Q','♡'], ['Q','♢'], ['Q','♤'], ['Q','♧']
// , ['K','♡'], ['K','♢'], ['K','♤'], ['K','♧']
// , ['A','♡'], ['A','♢'], ['A','♤'], ['A','♧']
// ]
flatMap
has been approved by the TC39 as part of ES2019 (ES10). You can use it like this:
[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
Here's my own implementation of the method:
const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])
MDN Article on flatMap
I know you said you didn't want to define it yourself, but this implementation is a pretty trivial definition.
There's also this from the same github page:
Here is a bit of shorter way using es6 spread, similiar to renaudtertrais's - but using es6 and not adding to the prototype.
var flatMap = (a, cb) => [].concat(...a.map(cb))
const s = (v) => v.split(',')
const arr = ['cat,dog', 'fish,bird']
flatMap(arr, s)
Would either of these help?
It should be noted (thanks to @ftor) that this latter "solution" suffers from "Maximum call stack size exceeded" if called on a really large (e.g., 300k elements) array a
.
Lodash provides a flatmap function, which to me is practically equivalent to Javascript providing it natively. If you're not a Lodash user, then ES6's Array.reduce()
method can give you the same result, but you have to map-then-flatten in discrete steps.
Below is an example of each method, mapping a list of integers and returning only the odds.
Lodash:
_.flatMap([1,2,3,4,5], i => i%2 !== 0 ? [i] : [])
ES6 Reduce:
[1,2,3,4,5].map(i => i%2 !== 0 ? [i] : []).reduce( (a,b) => a.concat(b), [] )
One fairly concise approach is to make use of the Array#concat.apply
:
const flatMap = (arr, f) => [].concat.apply([], arr.map(f))
console.log(flatMap([1, 2, 3], el => [el, el * el]));
I did somthing like this:
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]
We now have a flatMap()
in Javascript! And it is supported pretty well
The flatMap() method first maps each element using a mapping function, then flattens the result into a new array. It is identical to a map() followed by a flat() of depth 1
const dublicate = x => [x, x];
console.log([1, 2, 3].flatMap(dublicate))
Array.prototype.flatMap()
has now arrived in JS. However, not all browser might support them check for the current browser compatibility the Mozilla web docs.
What the flatMap()
method does is first maps each element using a callback function as argument, then flattens the result into a new array (the 2d array is now 1d since the elements are flattened out).
Here is also an example of how to use the function:
let arr = [[2], [4], [6], [8]]
let newArr = arr.flatMap(x => [x * 2]);
console.log(newArr);
本文标签: functional programmingWhy no ArrayprototypeflatMap in javascriptStack Overflow
版权声明:本文标题:functional programming - Why no Array.prototype.flatMap in javascript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736845850a1955295.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
arr.reduce((arr, v) => (arr.push(...v), arr), [])
? – Felix Kling Commented Oct 3, 2016 at 18:04arr.map(...).reduce(...)
). – Felix Kling Commented Oct 3, 2016 at 18:10.map
ping it. – kennytm Commented Oct 3, 2016 at 18:10