Как найти значения дублирования в многомерных массивах с помощью рекурсии - PullRequest
1 голос
/ 15 апреля 2020

У меня есть массив с именем A следующим образом:

  {
    name: 'activityRelatedManager',
    meta: {
      title: 'Activity Related Manager',
      permissions: []
    },
    children: [
      {
        name: 'activityPublish',
        meta: { title: 'Publish Activity', permissions:[] }
      },
      {
        name: 'activityManager',
        meta: { title: 'Manage Activity', permissions:[] }
      },
      {
        name: 'activityTypeManager',
        meta: { title: ' Manage Activity Type', permissions:[] }
      },
      {
        name: 'activityLocationManager',
        meta: { title: ' Manage Activity Location', permissions:[] }
      }
    ]
  },

У меня также есть массив с именем B, подобный этому:

[
    {
      "id": 1,
      "name": "activityRelatedManager",
      "permissions": [
        "activity:publish"
      ]
    },
    {
      "id": 2,
      "name": "activityManager",
      "permissions": [
        "activity:index",
        "activity:show"
      ]
    },
    {
      "id": 3,
      "name": "activityTypeManager",
      "permissions": []
    }
]

Что я хочу сделать, это найти дублированный значения, основанные на ключе «name» в B, а затем присваивают значение permissions A. Полученный результат должен выглядеть примерно так:

  {
    name: 'activityRelatedManager',
    meta: {
      title: 'Activity Related Manager',
      permissions: ["activity:publish"]
    },
    children: [
      {
        name: 'activityManager',
        meta: { title: 'Manage Activity', permissions:["activity:index", "activity:show"] }
      },
      {
        name: 'activityTypeManager',
        meta: { title: ' Manage Activity Type', permissions:[] }
      }
    ]
  },

Я думаю, что назначение легко, но как найти Дублирование?

  A.map(ele => {
    if (!ele.name || (!ele.meta && !ele.meta.permissions)) return
    for (let i = 0; i < B.length; i++) {
      const element = B[i]
      if (ele.name === element.name) {
        ele.meta.permissions = element.permissions
      }
    }
    if (ele.children) {
      makePermissionRouters(B, A.children)
    }
  })
  return clientAsyncRoutes

Буду признателен, если кто-нибудь поможет мне решить этот вопрос.

1 Ответ

0 голосов
/ 15 апреля 2020

Я бы выделил здесь служебную функцию, глубокую версию функции filterMap, которая принимает предикат и функцию преобразования и рекурсивно отфильтровывает каждый уровень дочерних элементов в соответствии с предикатом, а затем преобразует остальные с помощью предоставленная функция.

Вы можете использовать это, сначала переформатировав B для отображения - здесь мы называем это perms - между именами и списками разрешений, затем вызывая это deepFilterMap с предикатом, который проверяет если имя объекта в perms и преобразование, которое устанавливает meta.permissions в это значение.

Эта версия deepFilterMap задает c для структур, в которых узлы-потомки находятся в массиве с именем children. Мы могли бы сделать его более обобщенным c, но для этого потребовался бы другой параметр функции. Это интересное упражнение, но, возможно, здесь слишком много.

const deepFilterMap = (pred, transform) => (tree) =>
  pred (tree)
    ? {
        ... transform (tree), 
        ... (tree.children 
              ? {children: tree .children 
                                .filter (pred) 
                                .map (deepFilterMap (pred, transform))
                } 
              : {}
            )
      }
    : {}

const transform = (A, B) => {
  const perms = Object .fromEntries (B .map (
    ({name, permissions}) => [name, permissions])
  )

  return deepFilterMap (
    ({name}) => name in perms, 
    ({name, meta, ...rest}) => ({
      name, 
      meta: {...meta, permissions: perms [name]}, 
      ...rest
    })
  ) (A)
}

const A = {name: "activityRelatedManager", meta: {title: "Activity Related Manager", permissions: []}, children: [{name: "activityPublish", meta: {title: "Publish Activity", permissions: []}}, {name: "activityManager", meta: {title: "Manage Activity", permissions: []}}, {name: "activityTypeManager", meta: {title: " Manage Activity Type", permissions: []}}, {name: "activityLocationManager", meta: {title: " Manage Activity Location", permissions: []}}]};
const B = [{id: 1, name: "activityRelatedManager", permissions: ["activity: publish"]}, {id: 2, name: "activityManager", permissions: ["activity: index", "activity: show"]}, {id: 3, name: "activityTypeManager", permissions: []}];

console .log (transform (A, B))
.as-console-wrapper {min-height: 100% !important; top: 0}

Конечно, мы могли бы включить работу deepFilterMap в нашу основную функцию. В целом, у нас было бы меньше строк кода. Но, на мой взгляд, разбить сложность таким способом гораздо удобнее. И теперь у вас есть потенциально многократно используемая функция.

...