admin管理员组文章数量:1356774
I'm building a React app. I'm using Ramda to help me with functional programming.
If you want to see the full code, I also asked for help on StackExchange Code Review.
For Stack Overflow only one part is relevant, though.
How can you change a specific value from an object based on the object's other values using Ramda? I use mapObjIndexed
which in the process maps over all keys.
Context: I have on object representing a contact with several keys which are all strings. The object always has a key called contactDetails
. I want to calculate the value of contactDetails
dependant of the values of the object's tel
, bday
and email
keys.
If a contact looks like this before the function:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
it should look like this afterwards:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '[email protected] 555-55-5555',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
The function that I wrote for this looks like this:
R.mapObjIndexed((val, key, obj) =>
key === 'contactDetails'
? R.trim(
R.replace(
/undefined/g,
'',
`${R.prop('bday')(obj)} ${R.prop('tel')(obj)} ${R.prop('email')(
obj
)}`
)
)
: val
),
As you can see this is a pretty unclean and hacky way abusing map
. Is there a better way to change an object's value in Ramda based on other values of the object?
I'm building a React app. I'm using Ramda to help me with functional programming.
If you want to see the full code, I also asked for help on StackExchange Code Review.
For Stack Overflow only one part is relevant, though.
How can you change a specific value from an object based on the object's other values using Ramda? I use mapObjIndexed
which in the process maps over all keys.
Context: I have on object representing a contact with several keys which are all strings. The object always has a key called contactDetails
. I want to calculate the value of contactDetails
dependant of the values of the object's tel
, bday
and email
keys.
If a contact looks like this before the function:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
it should look like this afterwards:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '[email protected] 555-55-5555',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
The function that I wrote for this looks like this:
R.mapObjIndexed((val, key, obj) =>
key === 'contactDetails'
? R.trim(
R.replace(
/undefined/g,
'',
`${R.prop('bday')(obj)} ${R.prop('tel')(obj)} ${R.prop('email')(
obj
)}`
)
)
: val
),
As you can see this is a pretty unclean and hacky way abusing map
. Is there a better way to change an object's value in Ramda based on other values of the object?
3 Answers
Reset to default 8Unless this is an exercise in learning Ramda, I would suggest that a simpler technique than anything you're likely to e up with from Ramda is the straightforward object destructuring approach:
const transform = ({tel, bday, email, ...rest}) => ({
...rest, tel, bday, email,
contactDetails: [bday, email, tel].join(' ').trim()
})
const obj = {firstName: 'John', lastName: 'Doe', tel: '555-55-5555', bday: '', email: '[email protected]'}
console.log(transform(obj))
This version does not depend upon the key contactDetails
being already present, although it won't hurt if it is there.
If you're really worried about a possible double-space between words (for example, if bday
and tel
are supplied, but email
is empty), you can modify it to this:
const bine = (ss) => ss.reduce((a, s) => a + (s.length ? ' ' : '') + s, '').trim()
const transform = ({tel, bday, email, ...rest}) => ({
...rest, tel, bday, email,
contactDetails: bine([bday, email, tel])
})
I'm one of the founders of Ramda and a big fan, but it is only a toolkit. There are plenty of places where it helps make your code easier to read and to write; by all means use it then. But when it doesn't do so, even in a code-base heavily using Ramda, then skip it and use other techniques.
As an alternative to Ori's answer, we can update the property using R.assoc('contactDetails')
, building a list of the desired property values using R.juxt
and R.propOr('')
to default any missing properties, rejecting any empty strings before joining them together with R.join
.
// takes a list of property names, returning a function that accepts an object
// and produces a list of the values of the provided properties, defaulting to
// an empty string if null or undefined.
const defProps =
R.pose(R.juxt, R.map(R.propOr('')))
const fn =
// When `g` is a function, `R.chain(f, g)(x)` is equivalent to `f(g(x), x)`
R.chain(
R.assoc('contactDetails'),
R.pipe(
defProps(['bday', 'tel', 'email']),
R.reject(R.equals('')),
R.join(' ')))
console.log(fn({
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}))
<script src="https://cdnjs.cloudflare./ajax/libs/ramda/0.26.1/ramda.js"></script>
You can use R.converge to merge the original object, and the result of R.pipe that generates the contactDetails
property. The pipe gets an array of values via R.props, filters out falsy values (undefined, empty strings, nulls, etc...), joins the the items with spaces, and wrap the value with an object with R.objOf.
const { converge, merge, identity, pipe, props, filter, join, trim, objOf } = R
const fn = converge(merge, [identity, pipe(
props(['bday', 'tel', 'email']),
filter(Boolean),
join(' '),
objOf('contactDetails')
)])
const obj = {
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
const result = fn(obj)
console.log(result)
<script src="https://cdnjs.cloudflare./ajax/libs/ramda/0.26.1/ramda.js"></script>
本文标签:
版权声明:本文标题:javascript - Ramda: How to change only one value of an object, based the object's other values - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743957614a2568422.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论