Преобразование всех дочерних объектов с помощью рекурсивного сокращения в ES6 - PullRequest
3 голосов
/ 17 апреля 2019

Я пытаюсь создать набор редукторов, чтобы изменить атрибут всех объектов во вложенном списке.

Входная полезная нагрузка выглядит следующим образом:

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

Теперь я хочу изменить атрибут name всех элементов и дочерних элементов.

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

Как рекурсивно использовать эту функцию карты для всех дочерних элементов?

Я нашел способ сделать это, поместив рекурсию в одну и ту же функцию отображения.

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

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

Но мне бы хотелось, чтобы отображение имени было отделено от рекурсии (из-за того, что функции отображения были максимально простыми), и чтобы я мог связать их позже. Можно ли как-то сделать это с двумя редукторами, а затем связать их вместе?

Ответы [ 2 ]

2 голосов
/ 17 апреля 2019

Давайте начнем со строгого определения структур данных:

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

Теперь мы можем создать функции mapTree и mapForest:

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);

Надеюсь, это поможет.

1 голос
/ 17 апреля 2019

Создать рекурсивную функцию карты, которая отображает элемент и его детей (если существует). Теперь вы можете снабдить 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)
...