Ramda:如何根据对象的其他值仅更改对象的一个值
Ramda: How to change only one value of an object, based the object's other values
我正在构建一个 React 应用程序。我正在使用 Ramda 来帮助我进行函数式编程。
如果您想查看完整代码,我也在 StackExchange Code Review 上寻求帮助。
不过对于 Stack Overflow 只有一部分是相关的。
如何使用 Ramda 根据对象的其他值更改对象的特定值?我使用 mapObjIndexed
在过程中映射所有键。
上下文: 我有一个对象代表与几个键的联系,这些键都是字符串。该对象始终有一个名为 contactDetails
的键。我想根据对象的 tel
、bday
和 email
键的值计算 contactDetails
的值。
如果联系人在函数之前看起来像这样:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: 'john@doe.com'
}
之后应该是这样的:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: 'john@doe.com 555-55-5555',
tel: '555-55-5555',
bday: '',
email: 'john@doe.com'
}
我为此编写的函数如下所示:
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
),
如您所见,这是一种非常不干净和骇人听闻的滥用 map
的方式。有没有更好的方法来根据对象的其他值更改 Ramda 中对象的值?
您可以使用 R.converge 合并原始对象,以及生成 contactDetails
属性 的 R.pipe 结果。管道通过 R.props 获取值数组,过滤掉虚假值(未定义、空字符串、空值等),用空格连接项目,并用 [=24 的对象包装值=].
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: 'john@doe.com'
}
const result = fn(obj)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
除非这是学习 Ramda 的练习,否则我建议您使用简单的对象解构方法,这是一种比您可能从 Ramda 中得到的任何方法都更简单的方法:
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: 'john@doe.com'}
console.log(transform(obj))
此版本不依赖于密钥 contactDetails
已经存在,但如果它存在也不会造成伤害。
如果您真的担心单词之间可能出现双重 space(例如,如果提供了 bday
和 tel
,但 email
是空的), 你可以修改成这样:
const combine = (ss) => ss.reduce((a, s) => a + (s.length ? ' ' : '') + s, '').trim()
const transform = ({tel, bday, email, ...rest}) => ({
...rest, tel, bday, email,
contactDetails: combine([bday, email, tel])
})
我是 Ramda 的创始人之一,也是它的忠实粉丝,但它只是一个工具包。它在很多地方都有助于使您的代码更易于阅读和编写;一定要用它。但是当它不这样做时,即使在大量使用 Ramda 的代码库中,也可以跳过它并使用其他技术。
作为 Ori 答案的替代方案,我们可以使用 R.assoc('contactDetails')
更新 属性,使用 R.juxt
和 [=14] 构建所需 属性 值的列表=] 默认任何缺失的属性,在使用 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.compose(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: 'john@doe.com'
}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
我正在构建一个 React 应用程序。我正在使用 Ramda 来帮助我进行函数式编程。
如果您想查看完整代码,我也在 StackExchange Code Review 上寻求帮助。
不过对于 Stack Overflow 只有一部分是相关的。
如何使用 Ramda 根据对象的其他值更改对象的特定值?我使用 mapObjIndexed
在过程中映射所有键。
上下文: 我有一个对象代表与几个键的联系,这些键都是字符串。该对象始终有一个名为 contactDetails
的键。我想根据对象的 tel
、bday
和 email
键的值计算 contactDetails
的值。
如果联系人在函数之前看起来像这样:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: 'john@doe.com'
}
之后应该是这样的:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: 'john@doe.com 555-55-5555',
tel: '555-55-5555',
bday: '',
email: 'john@doe.com'
}
我为此编写的函数如下所示:
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
),
如您所见,这是一种非常不干净和骇人听闻的滥用 map
的方式。有没有更好的方法来根据对象的其他值更改 Ramda 中对象的值?
您可以使用 R.converge 合并原始对象,以及生成 contactDetails
属性 的 R.pipe 结果。管道通过 R.props 获取值数组,过滤掉虚假值(未定义、空字符串、空值等),用空格连接项目,并用 [=24 的对象包装值=].
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: 'john@doe.com'
}
const result = fn(obj)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
除非这是学习 Ramda 的练习,否则我建议您使用简单的对象解构方法,这是一种比您可能从 Ramda 中得到的任何方法都更简单的方法:
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: 'john@doe.com'}
console.log(transform(obj))
此版本不依赖于密钥 contactDetails
已经存在,但如果它存在也不会造成伤害。
如果您真的担心单词之间可能出现双重 space(例如,如果提供了 bday
和 tel
,但 email
是空的), 你可以修改成这样:
const combine = (ss) => ss.reduce((a, s) => a + (s.length ? ' ' : '') + s, '').trim()
const transform = ({tel, bday, email, ...rest}) => ({
...rest, tel, bday, email,
contactDetails: combine([bday, email, tel])
})
我是 Ramda 的创始人之一,也是它的忠实粉丝,但它只是一个工具包。它在很多地方都有助于使您的代码更易于阅读和编写;一定要用它。但是当它不这样做时,即使在大量使用 Ramda 的代码库中,也可以跳过它并使用其他技术。
作为 Ori 答案的替代方案,我们可以使用 R.assoc('contactDetails')
更新 属性,使用 R.juxt
和 [=14] 构建所需 属性 值的列表=] 默认任何缺失的属性,在使用 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.compose(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: 'john@doe.com'
}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>