【问题标题】:Transform all child objects using recursive reduce in ES6在 ES6 中使用递归 reduce 转换所有子对象
【发布时间】:2019-09-07 04:00:45
【问题描述】:

我正在尝试创建一组化简器以更改嵌套列表中所有对象的属性。

输入负载如下所示:

const payload = [
  {
    name: "Peter",
    children: [
      {
        name: "Sarah",
        children: [
          {
            name: "Sophie",
            children: [
              {
                name: "Chris"
              }
            ]
          }
        ]
      }
    ]
  }
];

我现在想更改所有元素和子元素的name 属性。

const mapJustNickname = elem => {
  return {
    ...elem,
    nickname: elem.name + "y"
  };
};

如何在所有子元素上递归使用这个 map 函数?

我找到了一种方法,将递归放在同一个映射函数中。

const mapToNickname = (elem) => {
    return {
    nickname: elem.name +'y',
    children: elem.children && elem.children.map(mapToNickname)
  }
}

console.log(payload.map(mapToNickname));

但我希望将名称的映射与递归分开(出于使映射函数尽可能简单的原因)并能够稍后将它们链接起来。是否有可能使用两个减速器然后将它们链接在一起?

【问题讨论】:

    标签: javascript node.js ecmascript-6 functional-programming reduce


    【解决方案1】:

    让我们从严格定义数据结构开始:

    data Person = Person { name :: String, nickname :: Maybe String }
    
    data Tree a = Tree { value :: a, children :: Forest a }
    
    type Forest a = [Tree a]
    
    type FamilyTree = Tree Person
    
    type FamilyForest = Forest Person
    

    现在,我们可以创建mapTreemapForest 函数:

    const mapTree = (mapping, { children=[], ...value }) => ({
        ...mapping(value),
        children: mapForest(mapping, children)
    });
    
    const mapForest = (mapping, forest) => forest.map(tree => mapTree(mapping, tree));
    
    // Usage:
    
    const payload = [
      {
        name: "Peter",
        children: [
          {
            name: "Sarah",
            children: [
              {
                name: "Sophie",
                children: [
                  {
                    name: "Chris"
                  }
                ]
              }
            ]
          }
        ]
      }
    ];
    
    const mapping = ({ name }) => ({ name, nickname: name + "y" });
    
    const result = mapForest(mapping, payload);
    
    console.log(result);

    希望对您有所帮助。

    【讨论】:

    • 非常干净的解决方案,非常感谢您的帮助!
    【解决方案2】:

    创建一个映射项目的递归映射函数,它是子项(如果存在)。现在您可以为recursiveMap 提供您想要的任何转换器功能,并且转换器不需要处理树的递归性质。

    const recursiveMap = childrenKey => transformer => arr => {
      const inner = (arr = []) =>
        arr.map(({ [childrenKey]: children, ...rest }) => ({
          ...transformer(rest),
          ...children && { [childrenKey]: inner(children) }
        }));
        
      return inner(arr);
    };
    
    const mapNickname = recursiveMap('children')(({ name, ...rest }) => ({
      name,
      nickname: `${name}y`,
      ...rest
    }));
    
    const payload = [{"name":"Peter","children":[{"name":"Sarah","children":[{"name":"Sophie","children":[{"name":"Chris"}]}]}]}];
    
    const result = mapNickname(payload);
    
    console.log(result)

    【讨论】:

    • 很有趣,我很喜欢!你知道的图书馆里有吗?
    • 由于使用了标准的map和spread,你不需要任何库,但是你可以使用任何有map方法的库。
    • 我又玩了一点,这正是我的想法。非常感谢你的帮助!可能没有办法将第 3 - 6 行中的地图封装并移动到单独的const 对吧?
    • 您可以轻松地做到这一点,方法是删除部分应用程序,并拥有一个始终接收 3 个参数(childrenKey、transformer、arr)的函数。但是,我认为部分应用程序更易于使用。
    猜你喜欢
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 2021-05-11
    • 2019-10-12
    • 2021-12-27
    • 1970-01-01
    • 2019-07-14
    • 1970-01-01
    相关资源
    最近更新 更多