为什么javascript中没有Array.prototype.flatMap?

Ser*_*aev 57 javascript functional-programming

flatMap对集合非常有用,但javascript不提供Array.prototype.map.为什么?

有没有办法flatMap在javascript中以简单有效的方式模拟,无需flatMap手动定义?

Tha*_*you 72

为什么javascript中没有Array.prototype.flatMap?

因为编程不是魔术,每种语言都没有其他语言所具有的特征/原语

重要的是

JavaScript使您能够自己定义它

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 ]
Run Code Online (Sandbox Code Playgroud)

或者重写将两个循环折叠成一个循环

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))
Run Code Online (Sandbox Code Playgroud)

如果你想要它Array.prototype.flatMap,没有什么能阻止你

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))
Run Code Online (Sandbox Code Playgroud)

更新:Array.prototype它是原生ECMAScript的方式.它目前处于第3阶段.

  • @FengyangWang*"被认为更好"*是非常主观的.如果这是您自己的应用程序,并且您有理由扩展原型,那么它没有任何问题.如果它是您正在分发供其他人使用的库/模块/框架,那么我会同意您的意见.然而,评论不是讨论这个问题的地方 - 这个问题应该得到比评论中应该提供的更多的解释和细节. (10认同)
  • @SergeyAlaev或者考虑在默认命名空间中无数其他人中有`append`,`map`,`filter`,`foldl`,`foldr`的Racket.这并不是一个糟糕的做法,因为你听到有人说"全局变坏"或"扩大本地人是坏事" - 球拍是设计最好的语言之一.你只是不知道如何/何时适当地做到这一点. (5认同)
  • @SergeyAlaev re:*"想象地图作为一个全局函数"*哈哈我在很多实用函数上做到了这一点.我也使用箭头功能序列来讨论它们."丑陋"是主观的.你并没有支持你的"坏习惯"评论.您的评论告诉我,您对函数式编程几乎没有经验.采用像哈斯克尔这样的语言,前奏包括大量的"全局"...没有人说它是"丑陋"或"坏习惯".你只是不熟悉它. (3认同)

Kut*_*yel 43

我认为这是一个伟大的时刻宣布,flatMap提出TC39

并且还给出了我的方法实现(更像2017年;)

[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

请享用!

编辑:实际上,正确地知道它在第3阶段,因此很有可能进入下一个ES版本

  • @CarlWalsh对不起,我无法抗拒。“ flapMap”到底是什么?我想展平我的地图,而不是拍平它! (2认同)

Ala*_*mms 10

我知道你说你不想自己定义它,但这个实现是一个非常简单的定义.

在同一个github页面上也有这个:

这里有一些使用es6 spread的简短方法,类似于renaudtertrais - 但是使用es6而不是添加到原型中.

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

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

flatMap(arr, s)
Run Code Online (Sandbox Code Playgroud)

这些都有帮助吗?

应该注意(感谢@ftor)如果在非常大的(例如,300k元素)阵列上调用,后一种"解决方案"会遭受"超出最大调用堆栈大小" a.

  • 此实现可能会炸毁大型阵列的堆栈. (2认同)
  • 尝试`[] .concat(...(new Array(300000).fill(“ foo”)。map(x => x.toUpperCase())))`。当然,这是一个极端的案例。但是您至少应该提到它。 (2认同)

Mat*_*iba 5

Lodash提供了一个平面图功能,对我来说实际上相当于本机提供它的Javascript.如果你不是Lodash用户,那么ES6的Array.reduce()方法可以给你相同的结果,但你必须以不连续的步骤进行map-then-flatten.

下面是每个方法的示例,映射整数列表并仅返回赔率.

Lodash:

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

ES6减少:

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