2016-12-10 2 views
0

Я ищу в функциональном программировании, где у меня есть следующий код до сих пор:функционального программирования изменить два элемента в массиве

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

Как изменить как duration и position в той же функции, чтобы сделать их целыми?

После этого у меня была бы эта функция, когда я передаю индекс и обновляю все positions после этой точки.

В принципе, мне нравится смещать смещение «положение» в зависимости от объекта, где была изменена «продолжительность»?

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

Так я вроде застрял на том, как смещение позиции.

Любые советы очень ценятся.

ответ

1

Я хотел бы сделать что-то вроде этого, 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)) 
+0

хороший, идеальный – khinester

+0

ответ @ scott-sauyet довольно штопор хороший. его использование 'lift' с' concat' (хорошо с любой n-ary> 1 функцией) является супер мощным шаблоном для ramda при работе со списками. –

0

Для вас первый вопрос, это легко.

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

.map - это новая функция ES6, которая пересекает массив, а затем возвращает новый массив. (Не мутирует отображение массива, которое является функциональным программированием 101)

Для вашего второго, простите меня, если я ошибаюсь, но это звучит либо как .filter, либо .push.

1

Другой вариант, по образцу одного из @Ian Hoffman-Hicks, но с несколько иной общественной 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, хотя она выбирает take и drop над splitAt. Это может быть или не стоить того, чтобы вас задумали, но он, по крайней мере, показывает другой подход.

+0

спасибо за ответ, действительно хорош и узнал больше. – khinester