Как вернуть значение в рекурсивной функции цикла? - PullRequest
0 голосов
/ 08 января 2019

Вот код.

var temp = [
    { 
    slugs: ['men'], 
    children: [
      { slugs: ['men', 'tops'], children: [
        { slugs: ['men', 'tops', 'shirts'] },
        { slugs: ['men', 'tops', 'swe'] }
      ] },
      {
        slugs: ['men', 'bottoms'], children: [
          { slugs: ['men', 'bottoms', 'pants'] },
          { slugs: ['men', 'bottoms', 'under'] }
        ]
      }
    ] 
  },
  {
    slugs: ['women'], 
    children: [
      { slugs: ['women', 'tops'], children: [
        { slugs: ['women', 'tops', 'shirts'] },
        { slugs: ['women', 'tops', 'swe'] }
      ] },
      {
        slugs: ['women', 'bottoms'], children: [
          { slugs: ['women', 'bottoms', 'pants'] },
          { slugs: ['women', 'bottoms', 'under'] }
        ]
      }
    ] 
  }
]

function matchTreeObj (tree, location) {
  if (_.isArray(tree) && tree.length > 0) {
    for(let i=0;i<tree.length;i++){
        matchTreeObj(tree[i], location)
    }
  }
  if (tree.slugs && (tree.slugs.join('/') === location)) {
    console.log(tree)
    return tree
  } else if (tree.children && tree.children.length > 0) {
    matchTreeObj(tree.children, location)
  }
}
const aaa = matchTreeObj(temp, 'men/tops')

console.log('from log', aaa)

Он использует lodash и скрипка здесь.
Код в основном выводит блок объекта, значение которого slugs соответствует параметру location.
Я мог бы получить консольный журнал работает должным образом. Но я не могу получить возвращенные данные. (Я уже пытался вернуть функцию, где я использую ее рекурсивно, и до сих пор не работает.)
Что я сделал не так?

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Хорошая возможность узнать о взаимной рекурсии - В математике и информатике взаимная рекурсия - это форма рекурсии, в которой два математических или вычислительных объекта, такие как функции или типы данных, определяются в терминах друг с другом. Взаимная рекурсия очень распространена в функциональном программировании и в некоторых проблемных областях, таких как парсеры рекурсивного спуска, где типы данных естественным образом взаимно рекурсивны -

type node =
  { slugs : string array
  , children : node array
  }

Каждый узел имеет свойство children , которое представляет собой массив узлов, каждый из которых имеет свойство children , содержащее еще больше узлов. Итак, у вас есть рекурсивная структура данных и хорошее время для применения техники взаимной рекурсии.

Ниже match вызывает match1, что, в свою очередь, вызывает match. Обе функции написаны с использованием чистого выражения. Цикл for не требуется, поскольку for является оператором, основан на побочном эффекте и используется в императивном стиле. Функциональный стиль позволяет избежать побочных эффектов и поэтому предпочитает рекурсию вместо for петель -

const None =
  Symbol ()

const EmptyNode =
  { slugs: []
  , children: []
  }

const match1 = (s = "", node = EmptyNode) =>
  node.slugs .join ('/') === s
    ? node
    : match (s, node.children)

const match = (s = "", [ node = None, ...rest ] = []) =>
  node === None
    ? undefined
    : match1 (s, node) || match (s, rest)

console .log
  ( match ("men/tops", data)       // { slugs: [ men, tops ], ... }
  , match ("women/bottoms", data)  // { slugs: [ women, bottoms ], ... }
  , match ("cat/dog", data)        // undefined
  )

Небольшая адаптация позволяет нам собирать все результаты вместо остановки после первого матча -

const EmptyNode =
  { slugs: []
  , children: []
  }

const match1 = (s = "", node = EmptyNode) =>
  node.slugs .join ('/') === s
    ? [ node, ...match (s, node.children) ]
    : match (s, node.children)

const match = (s = "", nodes = []) =>
  nodes .flatMap (x => match1 (s, x))

console .log
  ( match ("men/tops", data) // [ ... all matches ... ]
  , match ("cat/dog", data)  // []
  )

Эй, смотри, мы вернули значение , даже не используя return. Спасибо, функциональный стиль.

0 голосов
/ 08 января 2019

При переборе массива в цикле for проверьте вывод вызова matchTreeObj - если он верен, верните его:

for(let i=0;i<tree.length;i++){
  const result = matchTreeObj(tree[i], location)
  if (result) return result;
}

Также верните рекурсивный вызов в нижнем else if:

} else if (tree.children && tree.children.length > 0) {
  return matchTreeObj(tree.children, location)
}

var temp = [
	{ 
  	slugs: ['men'], 
    children: [
      { slugs: ['men', 'tops'], children: [
        { slugs: ['men', 'tops', 'shirts'] },
        { slugs: ['men', 'tops', 'swe'] }
      ] },
      {
        slugs: ['men', 'bottoms'], children: [
          { slugs: ['men', 'bottoms', 'pants'] },
          { slugs: ['men', 'bottoms', 'under'] }
        ]
      }
    ] 
  },
  {
  	slugs: ['women'], 
    children: [
      { slugs: ['women', 'tops'], children: [
        { slugs: ['women', 'tops', 'shirts'] },
        { slugs: ['women', 'tops', 'swe'] }
      ] },
      {
        slugs: ['women', 'bottoms'], children: [
          { slugs: ['women', 'bottoms', 'pants'] },
          { slugs: ['women', 'bottoms', 'under'] }
        ]
      }
    ] 
  }
]

function matchTreeObj (tree, location) {
  if (_.isArray(tree) && tree.length > 0) {
    for(let i=0;i<tree.length;i++){
    	const result = matchTreeObj(tree[i], location)
      if (result) return result;
    }
  }
  if (tree.slugs && (tree.slugs.join('/') === location)) {
    return tree
    } else if (tree.children && tree.children.length > 0) {
      return matchTreeObj(tree.children, location)
    }
}
const aaa = matchTreeObj(temp, 'men/tops')

console.log('from log', aaa)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.core.min.js"></script>

Логика может быть проще для понимания с первого взгляда, если вы разделите итерацию массива и тестирование объекта, и вам не понадобится большая библиотека для этого:

var temp=[{slugs:['men'],children:[{slugs:['men','tops'],children:[{slugs:['men','tops','shirts']},{slugs:['men','tops','swe']}]},{slugs:['men','bottoms'],children:[{slugs:['men','bottoms','pants']},{slugs:['men','bottoms','under']}]}]},{slugs:['women'],children:[{slugs:['women','tops'],children:[{slugs:['women','tops','shirts']},{slugs:['women','tops','swe']}]},{slugs:['women','bottoms'],children:[{slugs:['women','bottoms','pants']},{slugs:['women','bottoms','under']}]}]}];

function matchArr(arr, location) {
  for (const item of arr) {
    const result = matchItem(item, location);
    if (result) return result;
  }
}
function matchItem(item, location) {
  if (item.slugs.join('/') === location) {
    return item;
  } else if (item.children) {
    return matchArr(item.children, location);
  }
}
const output = matchArr(temp, 'men/tops')
console.log(output);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...