函数式编程修改数组中的两项

functional programming modify two items in an array

我正在研究函数式编程,到目前为止我有以下代码:

const R   = require('ramda')
const original = {
  words: [
    { duration: '0.360000', name: 'Arthur', position: '0.660000' },
    { duration: '0.150000', name: 'the',    position: '1.020000' },
    { duration: '0.380000', name: 'rat',    position: '1.170000' },
    { duration: '0.770000', name: '.',      position: '1.550000' }
  ]
}

// 1. convert position and duration to int and multiply by 100
const makeInteger = a => parseFloat(a) * 100

const words = R.lensPath(['words'])
log('position', R.over(words, R.map(R.over(position, makeInteger)), original).words)

returns:

position: [
    {
        duration: '0.360000',
        name: 'Arthur',
        position: 66
    },
    {
        duration: '0.150000',
        name: 'the',
        position: 102
    },
    {
        duration: '0.380000',
        name: 'rat',
        position: 117
    },
    {
        duration: '0.770000',
        name: '.',
        position: 155
    }
]

如何在同一函数中同时修改 durationposition 以使它们成为整数?

之后,我将使用此函数传递索引并更新该点之后的所有 positions

基本上我喜欢根据修改 'duration' 的对象移动 'position' 偏移量?

const pos = R.over(words, R.map(R.over(position, makeInteger)), original)
const y = (i) => R.slice(i, Infinity, pos.words)
const foo = R.adjust(R.add(-2), 0, y(1))
log(foo)

我得到了

[
    NaN,
    {
        duration: '0.150000',
        name: 'the',
        position: 102
    },
    {
        duration: '0.380000',
        name: 'rat',
        position: 117
    },
    {
        duration: '0.770000',
        name: '.',
        position: 155
    }
]

所以我有点卡在如何偏移位置上。

非常感谢任何建议。

第一个问题,很简单。

const parsedList = words.map(word => {
    return {
        duration:parseInt(word.duration)*100,
        name,word.name,
        position: parseInt(word.position)*100
    }
})

.map 是一个新的 ES6 函数,它循环一个数组,然后 returns 一个新数组。 (不改变它映射的数组,这是函数式编程 101)

对于你的第二个,如果我错了请原谅我,但听起来 .filter 或 .push 都可以。

我会做这样的事情,evolvesplitAt是你的好朋友:

const {
  lensProp, lensIndex, splitAt, compose,
  curry, flatten, add, map, multiply,
  over, evolve
} = require('ramda')

const original = {
  words: [
    { duration: '0.360000', name: 'Arthur', position: '0.660000' },
    { duration: '0.150000', name: 'the',    position: '1.020000' },
    { duration: '0.380000', name: 'rat',    position: '1.170000' },
    { duration: '0.770000', name: '.',      position: '1.550000' }
  ]
}

const words = lensProp('words')
const snd = lensIndex(1)

const makeInt =
  compose(multiply(100), parseFloat)

const updateProps =
  evolve({ duration: makeInt, position: makeInt })

const offsetPos =
  offset => evolve({ duration: add(offset), position: add(offset) })

const wordsToInt =
  over(words, map(updateProps))

const offsetTail = curry(
  (offset, list) => over(snd, map(offsetPos(offset)))(list)
)

const applyOffset = curry(
  (indx, offset, list) => compose(
    flatten,
    offsetTail(offset),
    splitAt(indx)
  )(list)
)

const offsetWords = curry(
  (indx, offset, obj) =>
    over(words, applyOffset(indx, offset))(obj)
)

const flow =
  compose(offsetWords(2, -2), wordsToInt)

log(flow(original))

另一个版本,以 @Ian Hoffman-Hicks 中的版本为蓝本,但略有不同 public API(flow 接受所有三个参数)和几个较少的中间函数,看起来像这样:

const wordsLens = lensProp('words') 

const makeInt = compose(multiply(100), parseFloat)

const offsetWords = curry((idx, offset, obj) => over(
  wordsLens, 
  lift(concat)(
    take(idx), 
    compose(
      map(evolve({position: add(offset)})), 
      drop(idx)
    )
  ), 
  obj
))

const flow = curry((idx, offset, obj) => offsetWords(
  idx, 
  offset, 
  over(
    wordsLens, 
    map(evolve({duration: makeInt, position: makeInt})), 
    obj
  )
))

flow(2, -2, original)

您可以在 Ramda REPL.

上看到实际效果

这个版本也使用了evolve, although it chooses take and drop over splitAt。这可能值得也可能不值得您考虑,但它至少展示了一种不同的方法。