Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm a novice to JS. Please, help me write a good function for my web application.

I have an array of "sayings" – objects kind of

 story = [
    {   letters:'B',
        head:'heading',
        text:'text',
        img:'img'
    },
    {   letters:'B|A',
        head:'heading',
        text:'text',
        img:'img'
    },
    {   letters:'B|A|E',
        head:'heading',
        text:'text',
        img:'img'
    },
    { 
        letters:'K|A',
        head:'heading',
        text:'text',
        img:'img'
    },
    { 
        letters:'K',
        head:'heading',
        text:'text',
        img:'img'
    }]

The 'letters' property is an address of the "saying" in a nested tree. The address consists of any number of capital letters, no numbers or special symbols are allowed. The | is a divider. I need to write a function to convert this array to a tree kind of:

  tree = [
    {   letter:'B', 
        letters:'B',
        head:'heading',
        text:'text',
        img:'img'
        nest: [{   letter:'A',
                   letters:'B|A',
                   head:'heading',
                   text:'text',
                   img:'img'
                   nest:[{   letter:'E', 
                              letters:'B|A|E',
                              head:'heading',
                              text:'text',
                              img:'img'
                          }]
               }]

    },
    {   letter:'K',
        letters:'K',
        head:'heading',
        text:'text',
        img:'img'
        nest:[{ letter:'A',
                letters:'K|A',
                head:'heading',
                text:'text',
                img:'img'
              }]
    }]

I understand that recursive function is needed here, but it's too difficult for me to figure out how the function can effectively convert the array without loosing "sayings" with child addresses coming before their parents. The function has to be fast for converting big arrays to trees on the fly in AngularJS web application.

Thanks for your help!

share|improve this question

1 Answer 1

up vote 0 down vote accepted

I hope you don't mind I use an object ({}) to represent the tree instead of an Array ([]), this makes searching for existing letters easier, and since each series of letters only has 1 root (letter), I think this makes sense. You do not actually need recursion in this case, since your initial entries are just a flat list which we can iterate once. I tested this in Node.js which uses the V8 JavaScript engine. Using an object with letter keys does make the 'letter' entry in the object itself kind of superfluous by the way.

var tree = {};

for(var i = 0; i < story.length; i++) {
    var saying = story[i];
    var letters = saying.letters.split('|');

    var search = tree;
    for(var j = 0; j < letters.length; j++) {
        var letter = letters[j];

        var obj = letter in search ? search[letter] : search[letter] = {};

        // Endpoint, assign letter and values to obj
        if(j == letters.length - 1) { 
            obj.letter = letter;
            for(key in saying) {
                obj[key] = saying[key];
            }
        } else { // Create nested object and update search object
            search = 'nest' in obj ? obj.nest : obj.nest = {};
        }
    }
};

// Output:
// { B: 
//    { letter: 'B',
//      letters: 'B',
//      head: 'heading',
//      text: 'text',
//      img: 'img',
//      nest: 
//       { A: 
//          { letter: 'A',
//            letters: 'B|A',
//            head: 'heading',
//            text: 'text',
//            img: 'img',
//            nest: 
//             { E: 
//                { letter: 'E',
//                  letters: 'B|A|E',
//                  head: 'heading',
//                  text: 'text',
//                  img: 'img' } } } } },
//   K: 
//    { nest: 
//       { A: 
//          { letter: 'A',
//            letters: 'K|A',
//            head: 'heading',
//            text: 'text',
//            img: 'img' } },
//      letter: 'K',
//      letters: 'K',
//      head: 'heading',
//      text: 'text',
//      img: 'img' } }
share|improve this answer
    
Yeah, that works good for me! Thought Angular needs to use an array in ng-repeat directive, but it works good with the object, that you suggest. Seems that there can be some difficulties with sorting the output, but I'm not sure yet. –  Denis Starov Apr 19 at 7:40
    
I checked the ng-repeat compatibility. The object works fine, but for sorting the output it should be an Array. BUT, there is a little filter for Angular, that makes it an array on the fly and everything works fine. Here it is: adamkdean.co.uk/blog/read/117/… Thank you very much, Daniël! –  Denis Starov Apr 19 at 14:51
    
Glad I could help :-) –  Daniël Knippers Apr 19 at 17:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.