1

Firstly I will try to explain situation.

I have categories array of objects which contains deeper objects and looks like this:

/*
    Categories

    Object variables legend:
    n - name, u - ID, p - category picture,
    s - sub categories
*/
    var Categories = [
        {n:'Category',u:1,p:'http://#',s:[{n:'Sub category',u:4,s:[{n:'Sub sub category',u:5,s:[],items:['sku','sku2']},{n:'Sub sub category 2',u:6,s:[],items:['sku','sku2']},{n:'Sub sub category 3',u:7,s:[],items:['sku','sku2']}],items:['sku','sku2']},{n:'Sub category',u:4,s:[{n:'Sub sub category',u:5,s:[]},{n:'Sub sub category 2',u:6,s:[]},{n:'Sub sub category 3',u:7,s:[]}]},{n:'Sub category',u:4,s:[{n:'Sub sub category',u:5,s:[]},{n:'Sub sub category 2',u:6,s:[]},{n:'Sub sub category 3',u:7,s:[]}]}],items:['sku','sku2']},
        {n:'Category',u:2,p:'http://#',s:[{n:'Sub category',u:8,s:[{n:'Sub sub category',u:9,s:[],items:['sku','sku2']},{n:'Sub sub category 2',u:10,s:[],items:['sku','sku2']},{n:'Sub sub category 3',u:11,s:[],items:['sku','sku2']}],items:['sku','sku2']}],items:['sku','sku2']},
        {n:'Category',u:3,p:'http://#',s:[{n:'Sub category',u:12,s:[{n:'Sub sub category',u:13,s:[],items:['sku','sku2']},{n:'Sub sub category 2',u:14,s:[],items:['sku','sku2']},{n:'Sub sub category 3',u:15,s:[],items:['sku','sku2']}],items:['sku','sku2']}],items:['sku','sku2']}
    ];

So basically sub categories, can have unlimited depth.. Now I need to write a function which will return value of items, when I will provide ID (which is u).

How should I achieve that, I could write multiple 'for' loops if I would know what the depth is, but I don't.

Is there some kind filtering function which I could adapt for this task?

1
  • 1
    basically, you're looking at a recursive search; However, your object isn't really all that normalized; the parent is an object with properties acting as array keys, but everything else follows items within the s node. Can categories be an array like one of the s values? Commented Jan 30, 2014 at 13:02

3 Answers 3

2

The first observation is that your Categories object is slightly irregular. Categories is a regular object which looks like an array, while the sub-categories are all arrays.

This would make it easier to work with:

var Categories = [
        {n:'Category',u:1,p:'http://#',s:[{n:'Sub category',u:4,s:[{n:'Sub sub category',u:5,s:[],items:['sku','sku2']},{n:'Sub sub category 2',u:6,s:[],items:['sku','sku2']},{n:'Sub sub category 3',u:7,s:[],items:['sku','sku2']}],items:['sku','sku2']},{n:'Sub category',u:4,s:[{n:'Sub sub category',u:5,s:[]},{n:'Sub sub category 2',u:6,s:[]},{n:'Sub sub category 3',u:7,s:[]}]},{n:'Sub category',u:4,s:[{n:'Sub sub category',u:5,s:[]},{n:'Sub sub category 2',u:6,s:[]},{n:'Sub sub category 3',u:7,s:[]}]}],items:['sku','sku2']},
        {n:'Category',u:2,p:'http://#',s:[{n:'Sub category',u:8,s:[{n:'Sub sub category',u:9,s:[],items:['sku','sku2']},{n:'Sub sub category 2',u:10,s:[],items:['sku','sku2']},{n:'Sub sub category 3',u:11,s:[],items:['sku','sku2']}],items:['sku','sku2']}],items:['sku','sku2']},
        {n:'Category',u:3,p:'http://#',s:[{n:'Sub category',u:12,s:[{n:'Sub sub category',u:13,s:[],items:['sku','sku2']},{n:'Sub sub category 2',u:14,s:[],items:['sku','sku2']},{n:'Sub sub category 3',u:15,s:[],items:['sku','sku2']}],items:['sku','sku2']}],items:['sku','sku2']}
    ]

Recursive solution:

function searchRecursive(needle, haystack) {
  for (var i=0; i<haystack.length; i++) {
    if (haystack[i].u === needle) return haystack[i];
    var search = searchRecursive(needle, haystack[i].s);
    if (search) return search;
  }
  return null;
}

// Usage:
searchRecursive(10, Categories) // Object {n: "Sub sub category 2", u: 10, s: Array[0], items: Array[2]}

Non-recursive solution:

function search(needle, haystack) {
  var queue = haystack.slice();

  while (queue.length) {
    var current = queue.shift();
    if (current.u === needle) return current;
    queue = queue.concat(current.s);
  }
  return null;
}

// Usage:
search(10, Categories) // Object {n: "Sub sub category 2", u: 10, s: Array[0], items: Array[2]}
Sign up to request clarification or add additional context in comments.

Comments

1

You have not Array of Objects, you have Object of Objects. You may need to change:

var Categories = {

to:

var Categories = [

Then you will need to iterate over your Array recursivelly:

function getU( obj, u ) {
    var result = null;
    for (var i = 0, len = obj.length; i < len; i++) {
        if (obj[i].u === u) {
            result = obj[i];
            break;
        }
    }
    if( result === null ) {
        result = getU( obj[ i ].s, u)
    }
    return result;
}

and First time calling it like:

getU( Categories, u);

Where u is your ID you want to find.

1 Comment

Thanks for notice about changing object to an array, your function works well with first level categories, but it does not check for id's (u) in subcategories, what makes the whole problem.
1

Now that you have a better format (more normalized data) your search becomes a lot easier:

function getU(obj, u){
    for (var i = 0, r; i < obj.length && !r; i++){
        if (obj[i].u == u) return obj[i];
        r = getU(obj[i].s, u);
    }
    return r;
}

So, for example:

getU(Categories, 6)
// returns: {"n":"Sub sub category 2","u":6,"s":[],"items":["sku","sku2"]}
getU(Categories, 14)
// returns: {"n":"Sub sub category 2","u":14,"s":[],"items":["sku","sku2"]}

// and of course (upper-most node)
getU(Categories, 1)
// returns {"n":"Category","u":1,"p":"http://#","s":[{"n":"Sub category","u":4,"s":[{"n":"Sub sub category","u":5,"s":[],"items":["sku","sku2"]},{"n":"Sub sub category 2","u":6,"s":[],"items":["sku","sku2"]},{"n":"Sub sub category 3","u":7,"s":[],"items":["sku","sku2"]}],"items":["sku","sku2"]},{"n":"Sub category","u":4,"s":[{"n":"Sub sub category","u":5,"s":[]},{"n":"Sub sub category 2","u":6,"s":[]},{"n":"Sub sub category 3","u":7,"s":[]}]},{"n":"Sub category","u":4,"s":[{"n":"Sub sub category","u":5,"s":[]},{"n":"Sub sub category 2","u":6,"s":[]},{"n":"Sub sub category 3","u":7,"s":[]}]}],"items":["sku","sku2"]}

2 Comments

Brad, Thank you for the answer. I ticked the other one, which was here faster, but I'm sure your answer will help for people out here too.
@Tautvydas: No worries. It's not a competition, and I won't go home unhappy because I got a blue ribbon. It's more important that you get your question answered and that you've accepted the answer you find complete and accurate. ;-)

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.