Оптимизировать вложенный массив из строк пути

1

Учитывая этот простой массив объектов:

var allPaths = [
  {path: "/", component: 'cmp-1'},
  {path: "/my-cool-list/", component: 'cmp-2'},
  {path: "/my-cool-list/this-is-card-1", component: 'cmp-3'},
  {path: "/my-cool-list/this-is-card-2", component: 'cmp-4'},
  {path: "/blog/", component: 'cmp-5'},
  {path: "/blog/2017/01/this-is-card-3", component: 'cmp-6'},
  {path: "/blog/2017/02/this-is-card-4", component: 'cmp-7'},
  {path: "/recettes/", component: 'cmp-8'},
  {path: "/recettes/this-is-card-5", component: 'cmp-9'},
  {path: "/recettes/this-is-card-6", component: 'cmp-10'}
]

Нужно произвести этот вывод:

[
  {
    path: "/", component: 'cmp-1'
  },
  {
    path: "/my-cool-list",
    component: 'cmp-2',
    children: [
      {path: "/this-is-card-1", component: 'cmp-3'},
      {path: "/this-is-card-2", component: 'cmp-4'}
    ]
  },

  {
    path: "/blog",
    component: 'cmp-5',
    children: [
      {
        path: "/2017",
        children: [
          {
            path: "/01",
            children: [
              {path: "/this-is-card-3", component: 'cmp-6'}
            ]
          },
          {
            path: "/02",
            children: [
              {path: "/this-is-card-4", component: 'cmp-7'}
            ]
          }
        ]
      }
    ]
  },

  {
    path: "/recettes",
    component: 'cmp-8',
    children: [
      {path: "/this-is-card-5", component: 'cmp-9'},
      {path: "/this-is-card-6", component: 'cmp-10'}
    ]
  },
]

Один из способов, который я нашел для этого, - это:

  1. пересекать каждый объект во всех allPaths
  2. создать допустимый вывод для каждого пути (например, если был предоставлен только этот путь)
  3. нажимать результирующий объект в массив с именем tree
  4. ...промыть и повторить...
  5. затем глубоко слить полученное tree в уникальное.

Код выглядит примерно так скрипку здесь:

let tree = []

// Recursive Tree Builder
const buildTree = (pathArray, ...others) => {
    var currentToken = pathArray.shift()
    var arr = []
    if (pathArray.length>0) {
       arr.push( {path: '/'+currentToken, children: []} )
       arr[0].children = buildTree(pathArray, ...others)
    } else {
       arr.push( Object.assign( {path: '/'+currentToken}, others[0] ))
    }
    return arr;  
}

// For each object in 'allPaths', build a tree
allPaths.map( page => {
   let {path, ...rest} = page    
   let res = buildTree(path.split('/').slice(1), rest)
   tree.push(res[0])
})

// external code to deeply merge each objects in 'tree' (external library: no need to put the code here but you got the point)

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

Чтобы сузить вопрос дальше, я попытался построить дерево "на лету", но я застрял, пытаясь надавить на точное местоположение в дереве. Например, сохранение ссылки на tree[0].children[0].children[0].children[0]... меня tree[0].children[0].children[0].children[0]... поскольку я не знаю, насколько глубже я узнаю связанный путь, или если children будут существуют на этом уровне.

Псевдокод (я думаю), будет:

  1. перемещать объекты allPaths один за другим

(притворяться, что первый пройденный объект имеет путь как /blog/level-2)

  1. найдите tree для 1-го уровня, найденного в path (например: /blog in /blog/level-2)

  2. не найдено? затем, нажмите объект в дереве

  3. этот путь имеет дополнительные уровни (например, в /blog/level-2)?

  4. .......да? идти на один уровень глубже (/level-2) в children и повторять с шага 3

  5. ....... нет? уровень сброса до 0. break

Теперь у меня возникают трудности с отслеживанием этих уровней: - Я не знаю, как легко запросить tree учетом пути: /blog/level-2 может быть у tree[2].children[14] или tree[32].children[57] и мне сложно запросить его, но более того, чтобы STORE эту информацию для дальнейшего использования.

Какие-нибудь мысли?

  • 1
    кажется это angular2 определение роутера. Почему бы вам не написать файл вручную вместо создания функции
  • 0
    Нет, извините, это никак не связано с Angular. :)
Теги:
ecmascript-6
arrays

1 ответ

0

Хорошо, я понял это сам.

const appendToTree = (tree, obj) => {
  // extract path from object
  let {path, ...rest} = obj

  // turn path into array of params
  let URLparams = path.split('/').slice(1)

  // recursive calls could send empty array
  if (URLparams.length === 0) return tree

  // take out first element in array: removes it from the array as well
  let currentURLparam = URLparams.shift()
  // reset path to what left in URLparams after shift
    path = '/' + URLparams.join('/')

  let currentPosition = 0, 
      currentNode = {},
      found = false

loopTree:  // find corresponding param in tree
  for(currentPosition; currentPosition < tree.length; currentPosition++) {
    if (tree[currentPosition].path === '/'+currentURLparam) {
       currentNode = tree[currentPosition]
       found = true
       break loopTree
    }
  }

  if(  found ) {  // found a matching path
    // get a reference to children or create an empty one
    currentNode['children'] = currentNode.children || []
    // repeat all, but with current reference and val which has been shifted before
    return appendToTree(currentNode.children, {path, ...rest})
  } else {  // not matching path found: insert it
    if (URLparams.length > 0) {  // still have URL params left ?
       // push current page object into array
       // Here we could force any default props to index levels
       let pos = tree.push({path: '/'+currentURLparam, children: []}) - 1
       // we still have params to process, so we proceed another iteration
       return appendToTree(tree[pos].children, {path, ...rest})
    } else { // no URL params left, this is the last one in stack
       tree.push({path: '/'+currentURLparam, ...rest})
       return tree
    }
  }
}



const buildTree = (tree, pages) => {
  // Traverse all pages objects and append each to provided tree
  pages.map(page => {
    appendToTree(tree, page)
  })
  return tree
}

Тогда нам просто нужно позвонить:

buildTree([], allPaths)

... он будет правильно создавать дерево "на лету", когда мы пересекаем каждый объект в allPaths. Чтобы решить мою проблему, я использовал рекурсию.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню