FP 方式的数组嵌套映射
Nested map of arrays the FP way
给定以下数组:
const array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"]
是否有任何 ramda 函数来简化以下我可以给出一个或多个数组的场景?
const nestedMap = map => {
const result = []
for(let item1 of array1)
for(let item2 of array2)
for(let item3 of array3)
result.push(map(item1, item2, item3))
return result
}
整个函数如下所示:
// Sample usage
nestedMap((item1, item2, item3) => `${item1} ${item2} ${item3}`, array1, array2, array3)
我希望避免重新发明轮子。
注意:Vanilla javascript 或任何其他库都可以接受。我最初谈到 ramda 因为它有很多功能,也许我错过了它可以帮助解决这个问题
您可以使用两步法,
- 构建所有产品
- 映射函数。
const
nestedMap = (fn, ...array) => array
.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []))
.map(a => fn(...a)),
array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"],
result = nestedMap((item1, item2, item3) => `${item1} ${item2} ${item3}`, array1, array2, array3)
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ramda 有一个 xprod
函数可以给出两个列表的叉积。像这样将它扩展到多个列表是相对简单的:
const xproduct = R.reduce(R.pipe(R.xprod, R.map(R.unnest)), [[]])
然后我们可以使用它来相对容易地创建嵌套地图函数:
const array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"]
const xproduct = R.reduce(R.pipe(R.xprod, R.map(R.unnest)), [[]])
const nestedMap = (fn, ...arrs) => R.map(R.apply(fn), xproduct(arrs))
console.log(nestedMap((a, b, c) => `${a}-${b}-${c}`, array1, array2, array3))
//==> ["a1-a2-a3", "a1-a2-b3", ...]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
您可以在此处使用数组的应用实例来简化 R.lift
您的函数:
const array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"]
const nestedMap = R.lift((item1, item2, item3) => `${item1} ${item2} ${item3}`)
console.log(nestedMap(array1, array2, array3))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
工作原理
这个答案通过向您展示直接在 Array
的原型上实现的 .ap
(和 .chain
),让您深入了解@ScottChristopher 的回复是如何工作的 – 作为练习!原型狂热者不要惊慌...
这里的想法是在一个代码片段中演示目标 behavior/output,该代码片段一次向您显示 所有 活动部分。只需~8行代码即可理解,恐吓系数相当低;与挖掘 Rambda 源代码之类的东西相比(实际上非常好)
我最近分享了 ,它使用定界延续做了一些非常相似的事情——如果你对这个答案感兴趣,我想你也会喜欢阅读那个 ^_^
// Array Applicative
Array.prototype.ap = function (...args)
{
const loop = (acc, [x,...xs]) =>
x === undefined
? [ this [0] (...acc) ]
: x.chain (a =>
loop (acc.concat ([a]), xs))
return loop ([], args)
}
// Array Monad
Array.prototype.chain = function chain (f)
{
return this.reduce ((acc, x) =>
acc.concat (f (x)), [])
}
const array1 = ['a1', 'b1', 'c1', 'd1']
const array2 = ['a2', 'b2']
const array3 = ['a3', 'b3', 'c3']
console.log ([ (x,y,z) => [x,y,z] ] .ap (array1, array2, array3))
// [ [ 'a1', 'a2', 'a3' ],
// [ 'a1', 'a2', 'b3' ],
// [ 'a1', 'a2', 'c3' ],
// [ 'a1', 'b2', 'a3' ],
// [ 'a1', 'b2', 'b3' ],
// [ 'a1', 'b2', 'c3' ],
// [ 'b1', 'a2', 'a3' ],
// [ 'b1', 'a2', 'b3' ],
// [ 'b1', 'a2', 'c3' ],
// [ 'b1', 'b2', 'a3' ],
// [ 'b1', 'b2', 'b3' ],
// [ 'b1', 'b2', 'c3' ],
// [ 'c1', 'a2', 'a3' ],
// [ 'c1', 'a2', 'b3' ],
// [ 'c1', 'a2', 'c3' ],
// [ 'c1', 'b2', 'a3' ],
// [ 'c1', 'b2', 'b3' ],
// [ 'c1', 'b2', 'c3' ],
// [ 'd1', 'a2', 'a3' ],
// [ 'd1', 'a2', 'b3' ],
// [ 'd1', 'a2', 'c3' ],
// [ 'd1', 'b2', 'a3' ],
// [ 'd1', 'b2', 'b3' ],
// [ 'd1', 'b2', 'c3' ] ]
给定以下数组:
const array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"]
是否有任何 ramda 函数来简化以下我可以给出一个或多个数组的场景?
const nestedMap = map => {
const result = []
for(let item1 of array1)
for(let item2 of array2)
for(let item3 of array3)
result.push(map(item1, item2, item3))
return result
}
整个函数如下所示:
// Sample usage
nestedMap((item1, item2, item3) => `${item1} ${item2} ${item3}`, array1, array2, array3)
我希望避免重新发明轮子。
注意:Vanilla javascript 或任何其他库都可以接受。我最初谈到 ramda 因为它有很多功能,也许我错过了它可以帮助解决这个问题
您可以使用两步法,
- 构建所有产品
- 映射函数。
const
nestedMap = (fn, ...array) => array
.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []))
.map(a => fn(...a)),
array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"],
result = nestedMap((item1, item2, item3) => `${item1} ${item2} ${item3}`, array1, array2, array3)
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ramda 有一个 xprod
函数可以给出两个列表的叉积。像这样将它扩展到多个列表是相对简单的:
const xproduct = R.reduce(R.pipe(R.xprod, R.map(R.unnest)), [[]])
然后我们可以使用它来相对容易地创建嵌套地图函数:
const array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"]
const xproduct = R.reduce(R.pipe(R.xprod, R.map(R.unnest)), [[]])
const nestedMap = (fn, ...arrs) => R.map(R.apply(fn), xproduct(arrs))
console.log(nestedMap((a, b, c) => `${a}-${b}-${c}`, array1, array2, array3))
//==> ["a1-a2-a3", "a1-a2-b3", ...]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
您可以在此处使用数组的应用实例来简化 R.lift
您的函数:
const array1 = ["a1", "b1", "c1", "d1"],
array2 = ["a2", "b2"],
array3 = ["a3", "b3", "c3"]
const nestedMap = R.lift((item1, item2, item3) => `${item1} ${item2} ${item3}`)
console.log(nestedMap(array1, array2, array3))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
工作原理
这个答案通过向您展示直接在 Array
的原型上实现的 .ap
(和 .chain
),让您深入了解@ScottChristopher 的回复是如何工作的 – 作为练习!原型狂热者不要惊慌...
这里的想法是在一个代码片段中演示目标 behavior/output,该代码片段一次向您显示 所有 活动部分。只需~8行代码即可理解,恐吓系数相当低;与挖掘 Rambda 源代码之类的东西相比(实际上非常好)
我最近分享了
// Array Applicative
Array.prototype.ap = function (...args)
{
const loop = (acc, [x,...xs]) =>
x === undefined
? [ this [0] (...acc) ]
: x.chain (a =>
loop (acc.concat ([a]), xs))
return loop ([], args)
}
// Array Monad
Array.prototype.chain = function chain (f)
{
return this.reduce ((acc, x) =>
acc.concat (f (x)), [])
}
const array1 = ['a1', 'b1', 'c1', 'd1']
const array2 = ['a2', 'b2']
const array3 = ['a3', 'b3', 'c3']
console.log ([ (x,y,z) => [x,y,z] ] .ap (array1, array2, array3))
// [ [ 'a1', 'a2', 'a3' ],
// [ 'a1', 'a2', 'b3' ],
// [ 'a1', 'a2', 'c3' ],
// [ 'a1', 'b2', 'a3' ],
// [ 'a1', 'b2', 'b3' ],
// [ 'a1', 'b2', 'c3' ],
// [ 'b1', 'a2', 'a3' ],
// [ 'b1', 'a2', 'b3' ],
// [ 'b1', 'a2', 'c3' ],
// [ 'b1', 'b2', 'a3' ],
// [ 'b1', 'b2', 'b3' ],
// [ 'b1', 'b2', 'c3' ],
// [ 'c1', 'a2', 'a3' ],
// [ 'c1', 'a2', 'b3' ],
// [ 'c1', 'a2', 'c3' ],
// [ 'c1', 'b2', 'a3' ],
// [ 'c1', 'b2', 'b3' ],
// [ 'c1', 'b2', 'c3' ],
// [ 'd1', 'a2', 'a3' ],
// [ 'd1', 'a2', 'b3' ],
// [ 'd1', 'a2', 'c3' ],
// [ 'd1', 'b2', 'a3' ],
// [ 'd1', 'b2', 'b3' ],
// [ 'd1', 'b2', 'c3' ] ]