首页 > 解决方案 > How can I deeply map over object with Ramda

问题描述

I'm trying to find all "template values" e.g. { template: 'Date: <now>'} using a map function to get this basic behaviour:

deepMap(mapFn, {a: 1, b: { c: 2, d: { template: 'Date: <now>'}}})

>> {a: 1, b: { c: 2, d: 'Date: 13423234232'}}

This is what I have so far. The interpolation of the template object does happen, but it does not replace the value.

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": {}}}

标签: javascriptramda.js

解决方案


问题是您deepMap再次调用映射值 - 但映射值不再是对象,而是字符串。

or(is(Array, val), is(Object, val))
        ? deepMap(fn, fn(val)) 
        : fn(val),

如果 val is { template: 'Date: <now>'},则 val 是一个对象,可以进行深度映射,但fn(val)它是一个 String ( "Date: 123123123"),应该简单地返回。一种解决方案是is检查映射值,而不是原始值:

(val, key) => {
      const mappedVal = fn(val);
      return or(is(Array, mappedVal), is(Object, mappedVal))
        ? deepMap(fn, mappedVal) 
        : mappedVal;
 },

另一种可能性是检查 map 函数是否返回了不同于原始值的值,并且在这种情况下不递归。


推荐阅读