我怎样才能用 Ramda 深度映射对象
How can I deeply map over object with Ramda
我正在尝试查找所有 "template values" 例如{ template: 'Date: <now>'}
使用 map 函数得到这个基本行为:
deepMap(mapFn, {a: 1, b: { c: 2, d: { template: 'Date: <now>'}}})
>> {a: 1, b: { c: 2, d: 'Date: 13423234232'}}
这就是我目前所拥有的。模板对象的插值确实发生,但它不会替换值。
const obj = {a: 1, b: { c: 2, d: { template: 'Date: <now>'}}};
const deepMap = (fn, xs) =>
mapObjIndexed(
(val, key, obj) =>
or(is(Array, val), is(Object, val))
? deepMap(fn, fn(val))
: fn(val),
xs
);
const checkFn = ({ template }) => template;
const transformFn = (val, key) => {
const interpolated = val.template.replace('<now>', Date.now())
console.log(interpolated);
return interpolated;
};
const mapFn = n =>
checkFn(n)
? transformFn(n)
: n;
console.clear();
deepMap(mapFn, obj);
>> {"a": 1, "b": {"c": 2, "d": {}}}
问题是您再次对映射值调用 deepMap
- 但映射值不再是对象,而是字符串。
or(is(Array, val), is(Object, val))
? deepMap(fn, fn(val))
: fn(val),
如果 val 是 { template: 'Date: <now>'}
,val 是一个对象并且可以被深度映射,但是 fn(val)
是一个字符串 ("Date: 123123123"
),应该简单地返回它。一种解决方案是 is
检查映射值,而不是原始值:
(val, key) => {
const mappedVal = fn(val);
return or(is(Array, mappedVal), is(Object, mappedVal))
? deepMap(fn, mappedVal)
: mappedVal;
},
另一种可能性是检查映射函数是否返回了原始值之外的其他内容,并且在这种情况下不要递归。
像这样的东西应该可以工作:
const {map, has, is} = R
const transformTemplate = ({template}) => template.replace('<now>', Date.now())
const deepMap = (xs) => map(x => has('template', x)
? transformTemplate(x)
: is(Object, x) || is(Array, x)
? deepMap(x)
: x, xs)
const result = deepMap({a: 1, b: { c: 2, d: { template: 'Date: <now>'}}})
// => {a: 1, b: {c: 2, d: "Date: 1542046789004"}}
console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
如果想传入转换函数,可以稍微改成
const deepMap = (transformer, xs) => map(x => has('template', x)
? transformer(x)
: is(Object, x) || is(Array, x)
? deepMap(transformer, x)
: x, xs)
const result = deepMap(transformTemplate, {a: 1, b: { c: 2, d: { template: 'Date: <now>'}}})
当然,您可以根据需要将其包装在 curry
中。
我现在没有时间研究为什么这种乍一看正确的方法不起作用。我希望这很简单:
const deepMap = map(cond([
[has('template'), transformTemplate],
[is(Object), deepMap],
[is(Array), deepMap],
[T, identity]
]))
我正在尝试查找所有 "template values" 例如{ template: 'Date: <now>'}
使用 map 函数得到这个基本行为:
deepMap(mapFn, {a: 1, b: { c: 2, d: { template: 'Date: <now>'}}})
>> {a: 1, b: { c: 2, d: 'Date: 13423234232'}}
这就是我目前所拥有的。模板对象的插值确实发生,但它不会替换值。
const obj = {a: 1, b: { c: 2, d: { template: 'Date: <now>'}}};
const deepMap = (fn, xs) =>
mapObjIndexed(
(val, key, obj) =>
or(is(Array, val), is(Object, val))
? deepMap(fn, fn(val))
: fn(val),
xs
);
const checkFn = ({ template }) => template;
const transformFn = (val, key) => {
const interpolated = val.template.replace('<now>', Date.now())
console.log(interpolated);
return interpolated;
};
const mapFn = n =>
checkFn(n)
? transformFn(n)
: n;
console.clear();
deepMap(mapFn, obj);
>> {"a": 1, "b": {"c": 2, "d": {}}}
问题是您再次对映射值调用 deepMap
- 但映射值不再是对象,而是字符串。
or(is(Array, val), is(Object, val))
? deepMap(fn, fn(val))
: fn(val),
如果 val 是 { template: 'Date: <now>'}
,val 是一个对象并且可以被深度映射,但是 fn(val)
是一个字符串 ("Date: 123123123"
),应该简单地返回它。一种解决方案是 is
检查映射值,而不是原始值:
(val, key) => {
const mappedVal = fn(val);
return or(is(Array, mappedVal), is(Object, mappedVal))
? deepMap(fn, mappedVal)
: mappedVal;
},
另一种可能性是检查映射函数是否返回了原始值之外的其他内容,并且在这种情况下不要递归。
像这样的东西应该可以工作:
const {map, has, is} = R
const transformTemplate = ({template}) => template.replace('<now>', Date.now())
const deepMap = (xs) => map(x => has('template', x)
? transformTemplate(x)
: is(Object, x) || is(Array, x)
? deepMap(x)
: x, xs)
const result = deepMap({a: 1, b: { c: 2, d: { template: 'Date: <now>'}}})
// => {a: 1, b: {c: 2, d: "Date: 1542046789004"}}
console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
如果想传入转换函数,可以稍微改成
const deepMap = (transformer, xs) => map(x => has('template', x)
? transformer(x)
: is(Object, x) || is(Array, x)
? deepMap(transformer, x)
: x, xs)
const result = deepMap(transformTemplate, {a: 1, b: { c: 2, d: { template: 'Date: <now>'}}})
当然,您可以根据需要将其包装在 curry
中。
我现在没有时间研究为什么这种乍一看正确的方法不起作用。我希望这很简单:
const deepMap = map(cond([
[has('template'), transformTemplate],
[is(Object), deepMap],
[is(Array), deepMap],
[T, identity]
]))