0

Here's the code.

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)

It's using lodash and fiddle is here.
The code basically ouputs the object chunk which its slugs value matches the location parameter.
I could get the console log works properly. But I can not get the returned data. (I already tried to return the function where I use it recursively, and still not work.)
What have I done wrong?

2 Answers 2

1

When iterating over the array in the for loop, check the output of calling matchTreeObj - if it's truthy, return it:

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

Also return the recursive call in the lower 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>

The logic might be easier to grasp at a glance if you separated out the array iteration and the object testing, though, and no need for a big library to accomplish this:

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

Sign up to request clarification or add additional context in comments.

Comments

1

A nice opportunity to learn about mutual recursion – In mathematics and computer science, mutual recursion is a form of recursion where two mathematical or computational objects, such as functions or data types, are defined in terms of each other. Mutual recursion is very common in functional programming and in some problem domains, such as recursive descent parsers, where the data types are naturally mutually recursive –

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

Each node has a children property which is an array of nodes, each of which have a children property containing even more nodes. So there you have it, a recursive data structure and a good time to apply a mutual recursion technique.

Below, match calls match1, which in turn calls match. Both functions are written using a pure expression. No for loop is necessary as for is a statement, relies on a side effect, and is used in imperative style. Functional stye avoids side effects and so favors recursion in place of for loops –

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
  )

A small adaptation allows us to collect all results instead of stopping after the first match -

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)  // []
  )

Hey look, we returned a value without even using return. Thanks, functional style.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.