flatMap
在集合中非常实用,但是javascript没有提供它,而却有Array.prototype.map
。为什么?
在javascript中是否有一种易于且高效的方式来模拟flatMap
而不需要手动定义flatMap
函数呢?
flatMap
在集合中非常实用,但是javascript没有提供它,而却有Array.prototype.map
。为什么?
在javascript中是否有一种易于且高效的方式来模拟flatMap
而不需要手动定义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 ]
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','♧']
// ]
Array.prototype._mylib_flatMap
)命名空间化,甚至更好的方法是使用ES6符号,而不是简单地定义Array.prototype.flatMap
。 - Fengyang Wangappend
、map
、filter
、foldl
、foldr
等无数实用函数。别因为听说“全局变量不好”或“扩展内置函数不好”就认为这种做法不好。Racket 是最优秀的语言之一,只是你需要知道什么时候以及如何恰当地使用它们。 - MulanflatMap
已经通过 ES2019(ES10)的 TC39 标准审查。您可以像这样使用它:
[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
这是我自己实现的方法:
const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])
flapMap
是什么意思?我想要展开我的地图,而不是拍打它! - ErikE我知道你说你不想亲自定义它,但是这个实现是一个相当简单的定义。
这个github页面还有这个:
这里有一种使用es6展开符号的更短的方法,类似于renaudtertrais的方法-但是使用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
上调用后面的“解决方案”,会出现“超过最大调用堆栈大小”的错误。
[].concat(...(new Array(300000).fill("foo").map(x => x.toUpperCase())))
。当然,这只是一个极端情况。但你至少应该提到它。 - user6445533Lodash 提供了一个 flatmap 函数,对我来说它几乎等同于 JavaScript 原生提供的该函数。如果你不是 Lodash 用户,则可以使用 ES6 的 Array.reduce()
方法获得相同的结果,但需要分步完成映射和展平操作。
以下是每种方法的示例,映射整数列表并仅返回奇数。
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), [] )
一个相对简洁的方法是利用Array#concat.apply
:
const flatMap = (arr, f) => [].concat.apply([], arr.map(f))
console.log(flatMap([1, 2, 3], el => [el, el * el]));
现在Javascript中有一个flatMap()
方法!而且它被很好地支持。
flatMap()
方法首先使用映射函数映射每个元素,然后将结果平铺到一个新数组中。它与深度为1的map()和flat()组合相同。
const dublicate = x => [x, x];
console.log([1, 2, 3].flatMap(dublicate))
{ "message": "Uncaught TypeError: [1,2,3].flatMap is not a function", "filename": "https://stacksnippets.net/js", "lineno": 15, "colno": 23 }
- SolutionMillArray.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]
Array.prototype.flatMap = function(selector){
if (this.length == 1) {
return selector(this[0]);
}
return this.reduce((prev, next) =>
(/*第一个*/ selector(prev) || /*除第一个之外的所有*/ prev).concat(selector(next)))
};
- JohnnyArray.prototype.flatMap()
现在已经出现在JS中。然而,并非所有浏览器都支持它们,请检查当前浏览器的兼容性Mozilla web docs。
flatMap()
方法的作用是首先使用回调函数作为参数映射每个元素,然后将结果展平为一个新数组(2D数组现在变成了1D,因为元素被展平了)。
这里还有一个如何使用该函数的示例:
let arr = [[2], [4], [6], [8]]
let newArr = arr.flatMap(x => [x * 2]);
console.log(newArr);
arr.reduce((arr, v) => (arr.push(...v), arr), [])
这样吗? - Felix Kling.map
操作后将数组压平。 - kennytm