0

I have an array of objects. The objects may have a property called children which inturn would include an array of objects. It is effectively a tree of objects.

var my_array_of_objects=[
  {
    "object_info": "blah blah",
    "children": [
      {
        "object_info": "blah blah",
        "children": [
          {
            "object_info": "blah blah"
          }
        ]
      }
    ]
  },
  {
    "object_info": "blah blah"
  },
  {
    "object_info": "blah blah"
  }
]

I am trying to recursively loop through the my_array_of_objects to return an array that will remove the tree architecture and give each object a relationship_id and a parent_relationship_id, however I am having a problem with the relationship_id getting set before the recursions happen and I can't see why... I assume it is a scoping issue?

  function sort_relationships(objects, return_objects, parent_relationship_id, relationship_id){
      $.each( objects, function( field_key, object ){
        relationship_id++;
        var new_object={};
        new_object.relationship_id=relationship_id;
        new_object.parent_relationship_id=parent_relationship_id;
        new_object.object_info=object.object_info;
        // PUSH OBJECT TO THE ARRAY TO BE RETURNED
        return_objects.push(new_object);
        // IF THE OBJECT HAS CHILDREN THEN RUN THE FUNCTION AGAIN WITH IT'S OBJECTS
        if(object.children instanceof Array){
          sort_relationships(object.children,return_objects,new_object.relationship_id,relationship_id);
        }
      });
      return return_objects;
  }

var my_new_array=sort_relationships(my_array_of_objects,[],0,0);

Based on the code above I would expect to have a unique relationship_id for each new object, however it is returning the following.

[
  {
    "relationship_id": 1,
    "parent_relationship_id": 0,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 2,
    "parent_relationship_id": 1,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 3,
    "parent_relationship_id": 2,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 2,
    "parent_relationship_id": 0,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 3,
    "parent_relationship_id": 0,
    "object_info": "blah blah"
  }
]

I would expect to have the following:

[
  {
    "relationship_id": 1,
    "parent_relationship_id": 0,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 2,
    "parent_relationship_id": 1,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 3,
    "parent_relationship_id": 2,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 4,
    "parent_relationship_id": 0,
    "object_info": "blah blah"
  },
  {
    "relationship_id": 5,
    "parent_relationship_id": 0,
    "object_info": "blah blah"
  }
]
4
  • can you include your expected output in your question. Commented Aug 28, 2016 at 13:54
  • @Rafi Ud Daula Refat .. Thnaks, I have added the expected results. Commented Aug 28, 2016 at 13:59
  • 1
    @Rafi Ud Daula Refat .. thanks for making the edit :) Commented Aug 28, 2016 at 14:04
  • It is as though the first set of relationship_id's are getting set before the recursion.. I imagine this is some kind of scoping issue?? Commented Aug 28, 2016 at 14:10

2 Answers 2

1

You're doing relationship_id++ on a variable that is local to each recursive call, and is not reflected at the caller. You either need to return the updated value, or just use a free variable:

function sort_relationships(objects) {
    var return_objects = [];
    var relationship_id = 0;
    function recurse(objects, parent_relationship_id) {
        $.each(objects, function(field_key, object) {
            relationship_id++;
            var new_object = {
                relationship_id: relationship_id,
                parent_relationship_id: parent_relationship_id,
                object_info: object.object_info
            };
            // PUSH OBJECT TO THE ARRAY TO BE RETURNED
            return_objects.push(new_object);
            // IF THE OBJECT HAS CHILDREN THEN RUN THE FUNCTION AGAIN WITH IT'S OBJECTS
            if (Array.isArray(object.children)) {
                recurse(object.children, new_object.relationship_id);
            }
        });
    }
    recurse(objects, 0);
    return return_objects;
}

var my_new_array=sort_relationships(my_array_of_objects);
Sign up to request clarification or add additional context in comments.

1 Comment

that's perfect, and thanks for your explanation although I'm not sure I fully understand. There a couple of typos in your code, new_object shouldn't have a closing ")" and it should be recurse(objects, 0); I will mark it as the correct answer as soon as I can:)... thanks again.
1

You could use reduce for this, and for the id (where things go wrong), you could add to the parent id the count of already accumulated objects:

function flatten(arr, parentId = 0) {
    if (!arr) return [];
    return arr.reduce ( function (acc, obj) {
        var rel = {
            object_info: obj.object_info,
            relationship_id: parentId + acc.length + 1,
            parent_relationship_id: parentId
        };
        return acc.concat([rel], flatten(obj.children, rel.relationship_id));
    }, []);
}

// sample data
var my_array_of_objects=[{
    "object_info": "blah blah",
    "children": [{
        "object_info": "blah blah",
        "children": [{
            "object_info": "blah blah"
          }
        ]
      }
    ]
  }, {
    "object_info": "blah blah"
  }, {
    "object_info": "blah blah"
  }
];

// convert
var result = flatten(my_array_of_objects);
// output
console.log(result);

2 Comments

thanks for your answer, it also works perfectly. If I could mark 2 questions as the answer I would, however Bergi answered first... thanks again for taking the time to answer, much appreciated. J
You're welcome, and of course no problem. Bergi is an expert :-)

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.