flatMap
在集合上非常有用,但是 javascript 在拥有Array.prototype.map
. 为什么?
有没有办法以flatMap
简单有效的方式在 javascript 中进行模拟而无需flatMap
手动定义?
flatMap
在集合上非常有用,但是 javascript 在拥有Array.prototype.map
. 为什么?
有没有办法以flatMap
简单有效的方式在 javascript 中进行模拟而无需flatMap
手动定义?
更新: Array.prototype.flatMap
进入 ES2019
它在许多环境中得到广泛支持。使用以下代码段查看它是否在您的浏览器中有效 -
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 ]
“为什么 JavaScript 中没有 Array.prototype.flatMap?”
因为编程不是魔术,而且每种语言都没有其他语言所具有的特性/原语。重要的是 JavaScript 让你能够自己定义它——
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))
或者重写将两个循环合二为一——
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))
如果你想让它延长Array.prototype
,没有什么能阻止你 -
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
已被 TC39 批准为 ES2019 (ES10) 的一部分。你可以这样使用它:
[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
这是我自己对该方法的实现:
const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])
我知道你说过你不想自己定义它,但这个实现是一个非常简单的定义。
还有来自同一个github页面的这个:
这是使用 es6 spread 的一种更短的方法,类似于 renaudtertrais's - 但使用 es6 而不是添加到原型中。
var flatMap = (a, cb) => [].concat(...a.map(cb))
const s = (v) => v.split(',')
const arr = ['cat,dog', 'fish,bird']
flatMap(arr, s)
这两个有帮助吗?
应该注意(感谢@ftor),如果在一个非常大的(例如,300k 个元素)数组上调用,后一种“解决方案”会受到“超出最大调用堆栈大小”的影响a
。
Lodash提供了一个 flatmap 函数,对我来说这实际上相当于 Javascript 原生提供它。如果您不是 Lodash 用户,那么 ES6 的Array.reduce()
方法可以为您提供相同的结果,但您必须以离散的步骤进行 map-then-flatten。
下面是每种方法的示例,映射整数列表并仅返回几率。
洛达什:
_.flatMap([1,2,3,4,5], i => i%2 !== 0 ? [i] : [])
ES6 减少:
[1,2,3,4,5].map(i => i%2 !== 0 ? [i] : []).reduce( (a,b) => a.concat(b), [] )
一种相当简洁的方法是使用Array#concat.apply
:
const flatMap = (arr, f) => [].concat.apply([], arr.map(f))
console.log(flatMap([1, 2, 3], el => [el, el * el]));