循环直到...使用 Ramda

Sir*_*ple 3 javascript functional-programming ramda.js

我试图使用 Ramda 重构几段代码,我想知道在 Ramda/Functional Programming 中解决以下代码的好方法是什么:

let arrayOfSomething = initArray();

for(let i = 0; SOME_INDEX_CONDITION(i)|| SOME_CONDITION(arrayOfSomething); i++) {
    const value = operation(arrayOfSomething);
    const nextValue = anotherOperation(value);

   arrayOfSomething = clone(nextValue)
}
Run Code Online (Sandbox Code Playgroud)

所以基本上我想迭代并在 arrayOfSomething 上应用相同的管道/操作组合,直到满足其中一个条件。重要的是我得到最后一个值 (nextValue) 作为对 forLoop 组合的反馈。

Sco*_*yet 5

我不知道这是否符合您的要求,但 Ramdauntil可能是您需要的:

const operation = ({val, ctr}) => ({val: val % 2 ? (3 * val + 1) : (val / 2), ctr: ctr + 1})

const indexCondition = ({ctr}) => ctr > 100
const valCondition = ({val}) =>  val === 1
const condition = R.either(indexCondition, valCondition)

const check = R.until(condition, operation)

const collatz = n => check({ctr: 0, val: n})

console.log(collatz(12)) 
// 12 -> 6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 //=> {"ctr": 9, "val": 1}
console.log(collatz(5)) 
// 5 -> 16 -> 8 -> 4 -> 2 -> 1 //=> {"ctr": 5, "val": 1}
console.log(collatz(27)) 
//27 -> 82 -> 41 -> 124 -> 62 -> .... //=> {"ctr": 101, "val": 160}
Run Code Online (Sandbox Code Playgroud)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
Run Code Online (Sandbox Code Playgroud)


Tha*_*you 5

看起来您正在寻找反向折叠,或unfold.

大多数人都熟悉reduce:它需要一组值并将其简化为单个值——unfold相反:它需要一个值并将其展开为一组值

其他更熟悉 Ramda 的人可以评论库中是否已经存在类似的函数

const unfold = (f, init) =>
  f ( (x, next) => [ x, ...unfold (f, next) ]
    , () => []
    , init
    )

const nextLetter = c =>
  String.fromCharCode (c.charCodeAt (0) + 1)

const alphabet =
  unfold
    ( (next, done, c) =>
        c > 'z'
          ? done ()
          : next (c, nextLetter (c))
    , 'a'
    )

console.log (alphabet)
// [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z ]
Run Code Online (Sandbox Code Playgroud)

unfold 很强大

const fib = (n = 0) =>
  unfold
    ( (next, done, [ n, a, b ]) =>
        n < 0
          ? done ()
          : next (a, [ n - 1, b, a + b ])
    , [ n, 0, 1 ]
    )

console.log (fib (20))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765 ]
Run Code Online (Sandbox Code Playgroud)

我们可以实现您的iterateUntil使用unfold

const fib = (n = 0) =>
  unfold
    ( (next, done, [ n, a, b ]) =>
        n < 0
          ? done ()
          : next (a, [ n - 1, b, a + b ])
    , [ n, 0, 1 ]
    )

console.log (fib (20))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765 ]
Run Code Online (Sandbox Code Playgroud)

我们可以用async和让它轻松支持异步await。下面我们使用asyncUnfold从单个节点 id 开始执行递归数据库查找,0

  • db.getChildren接受一个节点id并只返回该节点的直接子节点

  • traverse接受一个节点id,它递归地获取所有后代子节点(以深度优先的顺序)

const unfold = (f, init) =>
  f ( (x, acc) => [ x, ...unfold (f, acc) ]
    , () => []
    , init
    )
    
const iterateUntil = (f, init) =>
  unfold
    ( (next, done, [ arr, i ]) =>
        i >= arr.length || f (arr [i], i, arr)
          ? done ()
          : next (arr [i], [ arr, i + 1 ])
    , [ init, 0 ]
    )
  
const data =
  [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ]
  
console.log (iterateUntil ((x, i) => i > 3, data))
// [ 'a', 'b', 'c', 'd' ]

console.log (iterateUntil ((x, i) => x === 'd', data))
// [ 'a', 'b', 'c', 'd' ]
Run Code Online (Sandbox Code Playgroud)

其他适合的程序 unfold

  • “从页面 URL 开始/,抓取所有后代页面”
  • “从搜索"foo"和页面开始1,收集所有页面的结果”
  • “从用户开始Alice,向我展示她的朋友,以及她所有朋友的朋友”

  • Ramda 确实有一个“展开”,但它确实需要一些工作。这是一个很好的答案! (2认同)