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

Javascript 函数式编程修改数组中的两个项,javascript,ramda.js,Javascript,Ramda.js,我正在研究函数式编程,目前为止我有以下代码: 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

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

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)
返回:

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
    }
]
如何在同一函数中修改
持续时间
位置
,使其成为整数

接下来,我将使用这个函数传递索引并更新该点之后的所有
位置

基本上,我喜欢根据修改“持续时间”的对象来移动“位置”偏移量

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函数,它在数组上循环,然后返回一个新数组。(不改变其映射的数组,这是函数式编程101)


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

对于你的第一个问题,这很简单

const parsedList = words.map(word => {
    return {
        duration:parseInt(word.duration)*100,
        name,word.name,
        position: parseInt(word.position)*100
    }
})
.map是一个新的ES6函数,它在数组上循环,然后返回一个新数组。(不改变其映射的数组,这是函数式编程101)


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

我会这样做,
evolve
splitAt
是你的朋友:

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))

我会这样做,
evolve
splitAt
是你的朋友:

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))

另一个版本是以中的版本为模型的,但具有稍微不同的公共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)
您可以在上看到这一点


这个版本也被使用了,尽管它选择了并多次使用。这可能值得您考虑,也可能不值得您考虑,但它至少显示了一种不同的方法。

另一个版本,以来自的版本为模型,但具有稍微不同的公共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)
您可以在上看到这一点


这个版本也被使用了,尽管它选择了并多次使用。这对你来说可能值得考虑,也可能不值得考虑,但它至少显示了一种不同的方法。

不错,这很完美@scott sauyet的答案非常好。他使用
lift
concat
(以及任何n元>1函数)是拉姆达在处理列表时的一种超级强大的模式。不错,这是完美的@scott sauyet的答案非常好。他使用
lift
concat
(以及任何n元>1函数)是拉姆达在处理列表时的一种超级强大的模式。感谢您的回复,非常好,学到了更多。感谢您的回复,非常好,学到了更多。