【问题标题】:Nested map of arrays the FP wayFP方式的数组嵌套映射
【发布时间】:2018-03-21 19:10:42
【问题描述】:

给定以下数组:

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 因为它有很多功能,也许我错过了可以帮助解决这个问题的功能

【问题讨论】:

  • 所以,本质上我们正在寻找一个矩阵形式。正确的?如果您还可以添加示例输出,这将有所帮助。还有,纯JS函数可以接受吗?
  • 既然你在问函数式编程:为什么你的函数没有返回值?我没有看到任何mapping 在这里发生,这看起来更像是带有回调的多维forEach
  • @Bergi 抱歉,我已经修复了我的问题。现在它已经返回
  • @Rajesh 为什么不呢。我想明确一点,我不想获取如何使用 vanilla JS 来实现它的源代码,但如果你已经完成了一些事情,它也可能是可以接受的

标签: javascript arrays functional-programming ramda.js


【解决方案1】:

工作原理

此答案通过向您展示直接在 Array 的原型上实现的 .ap(和 .chain),让您深入了解 @ScottChristopher 的回复是如何工作的 - 作为练习! Don'别吓坏了,原型狂热者......

这里的想法是在代码 sn-p 中演示目标行为/输出,一次向您显示所有的移动部件。只需大约 8 行代码即可理解,恐吓系数非常低;与挖掘 Rambda 源代码相比(这实际上非常好)

我最近分享了@98​​7654321@,它使用定界延续做了非常相似的事情——如果你对这个答案感兴趣,我想你也会喜欢阅读那个^_^

// 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' ] ]

【讨论】:

    【解决方案2】:

    你可以在这里使用数组的应用实例来简单地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>

    【讨论】:

    【解决方案3】:

    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>

    【讨论】:

      【解决方案4】:

      您可以使用两步法,

      1. 构建所有产品
      2. 映射函数。

      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; }

      【讨论】:

        猜你喜欢
        • 2019-08-13
        • 1970-01-01
        • 2020-10-25
        • 2013-03-21
        • 1970-01-01
        • 2013-08-08
        • 2021-05-27
        • 2013-07-17
        • 2020-09-25
        相关资源
        最近更新 更多