10

I have a JSON input which can go to any number of levels.

I'm giving an input sample of

var d=getEntities( {"Categories": 
{
"Facets": 
    [
    {
    "count": 1,
    "entity": "Company",
    "Company": 
            [
            {

            "entity": "Ford Motor Co",

            "Ford_Motor_Co": 
                [
                    {
                    "count": 1,
                    "entity": "Ford"
                    }
                ]
            }
            ]
    },
        {
            "count": 4,
            "entity": "Country",
              "Country": [
                    {

                        "entity": "Germany",
                         "Germany": [
                                {
                                    "count": 1,
                                    "entity": "Germany"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                         "entity": "Italy",
                        "Italy": [
                                {
                                     "count": 1,
                                     "entity": "Italy"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                        "entity": "Japan",
                          "Japan": [
                             {
                                    "count": 1,
                                    "entity": "Japan"
                             }
                          ],
                        "currency": "Yen (JPY)"
                    },
                    {

                        "entity": "South Korea",
                          "South_Korea": [
                              {
                                    "count": 1,
                                    "entity": "South Korea"
                                }
                          ],
                      "currency": "Won (KRW)"
                    }
              ]
        },
        {"count": 5,
              "entity": "Persons",
              "Persons": [
                    {
                         "count": 2,
                        "entity": "Dodge"
                    },
                    {
                        "count": 1,
                        "entity": "Dodge Avenger"
                    },
                    {
                        "count": 1,
                        "entity": "Major League"
                    },
                    {
                        "count": 1,
                        "entity": "Sterling Heights"
                    }
              ]
        }
  ]

}});

I want to add the key value "Entity" in all levels to an array using recursion,

I'm able to collect the data from first level using the string

<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript" src="dataDumper.js"></script>


<script type="text/javascript">

var testJSON = {"Categories": 
{
"Facets": 
    [
    {
    "count": 1,
    "entity": "Company",
    "Company": 
            [
            {

            "entity": "Ford Motor Co",

            "Ford_Motor_Co": 
                [
                    {
                    "count": 1,
                    "entity": "Ford"
                    }
                ]
            }
            ]
    },
        {
            "count": 4,
            "entity": "Country",
              "Country": [
                    {

                        "entity": "Germany",
                         "Germany": [
                                {
                                    "count": 1,
                                    "entity": "Germany"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                         "entity": "Italy",
                        "Italy": [
                                {
                                     "count": 1,
                                     "entity": "Italy"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                        "entity": "Japan",
                          "Japan": [
                             {
                                    "count": 1,
                                    "entity": "Japan"
                             }
                          ],
                        "currency": "Yen (JPY)"
                    },
                    {

                        "entity": "South Korea",
                          "South_Korea": [
                              {
                                    "count": 1,
                                    "entity": "South Korea"
                                }
                          ],
                      "currency": "Won (KRW)"
                    }
              ]
        },
        {"count": 5,
              "entity": "Persons",
              "Persons": [
                    {
                         "count": 2,
                        "entity": "Dodge"
                    },
                    {
                        "count": 1,
                        "entity": "Dodge Avenger"
                    },
                    {
                        "count": 1,
                        "entity": "Major League"
                    },
                    {
                        "count": 1,
                        "entity": "Sterling Heights"
                    }
              ]
        }
  ]

}};

function scan(obj)
{
    var k;
    if (obj.hasOwnProperty('entity')) {



        for (k in obj){
           if (obj.hasOwnProperty(k)){


                scan( obj[k] );  


            }                
          }
    } 


    else{
        if(k=='entity')
        {
        alert(obj.entity);
   }
    }


};

scan(testJSON);



</script>
</head>

<body>

</body>

</html>

How do I get in to the inner levels for JSON string using recursive functions?

user1371896
  • 2,192
  • 7
  • 23
  • 32
  • Dont put an else in, put the if and alert before the call to scan – El Ronnoco May 06 '12 at 15:32
  • Thumbs up!!! And thanks a lot!!!! Really appreciate all your help.. – user1371896 May 06 '12 at 23:14
  • @ElRonnoco Ive been experimenting with this thing and do u knw hw we cn add entities in different levels in to same array.. ie entities in level 1 goes to one array, level 2 to nxt and so on.. – user1371896 May 07 '12 at 03:47
  • I'm not clear what you mean. You can add any new property to a Json object just by saying eg Main.new=1 will create a property 'new' in object Main. If you want to create a new Json object use {}. To create an array use []. to add a Json object to an array use myarray.push({}). To add an array to an array use myarray.push([]) – El Ronnoco May 07 '12 at 11:21
  • with out using "key", do you know how to perform the same operation using array... – user1371896 May 07 '12 at 11:24
  • Hey, how did my name end up on there? :P – Jerry Dodge Feb 13 '19 at 21:56

5 Answers5

22

I have made a jsfiddle which traverses every object,array and value in the JS object like so...

function scan(obj) {
    var k;
    if (obj instanceof Object) {
        for (k in obj){
            if (obj.hasOwnProperty(k)){
                //recursive call to scan property
                scan( obj[k] );  
            }                
        }
    } else {
        //obj is not an instance of Object so obj here is a value
    };

};

I get no recursion error (in Chrome). Can you use this to do what you want?

If you need to test if an object is an array use if (obj instanceof Array)

To test if an object has an "entity" property use if (obj.hasOwnProperty('entity'))

To add (or modify an existing) "entity" property use obj.entity = value or obj['entity'] = value

OCDev
  • 2,280
  • 3
  • 26
  • 37
El Ronnoco
  • 11,753
  • 5
  • 38
  • 65
  • 1
    I've answered this on my iPhone so if someone could fix my formatting i'd be very grateful!!! – El Ronnoco May 05 '12 at 08:22
  • its showing the error,if is nt defined for If (h.hasOwnProperty(k)) – user1371896 May 05 '12 at 08:24
  • Ah you may new to test for 'if (h instanceof object)' before entering the loop. – El Ronnoco May 05 '12 at 08:30
  • no,,,it ws the format of ur code...I was in big letter.. It now alerts first entity Company and then shows "too much recursion " for getEntities(h[k]); – user1371896 May 05 '12 at 08:32
  • Sorry I'm using a phone! Yes but the routine will iterate through every level, you will need to add logic to restrict recursion to meet your requirement. I didn't fully understand your question and I can't see your Json properly. – El Ronnoco May 05 '12 at 08:46
  • I would be realy grateful if u cud help me later with this thing.. I will try to find a stop expression to restrict the recursion. – user1371896 May 05 '12 at 08:50
  • 1
    The "stop expression" is the one I used in my answer: `if ( ({}).toString.apply( prop ) === '[object Object]' ) {`. Btw, `Object.keys` returns an array of the enumerable properties, so it is not needed to use `hasOwnProperty`. – Florian Margaine May 05 '12 at 09:09
  • How deep is your object nested? I'm not sure how many levels of recursion JS supports. @florian that's a good tip thanks. – El Ronnoco May 05 '12 at 12:21
  • That's unusual, are you running in firefox? Any JS engine should easily handle 3 levels deep!... – El Ronnoco May 05 '12 at 12:47
  • @ElRonnoco Ive edited the question part to add the program that Ive wrote... You can check out if its wrking by copying it and saving as html file.. – user1371896 May 05 '12 at 13:19
  • @ElRonnoco This will solve my prblem, thanks a lot!!! bt one last thing... I need only the values of Entity key, so I tried if (obj.hasOwnProperty('entity')) instead of if (obj.hasOwnProperty(k)), bt it dint wrk!! – user1371896 May 06 '12 at 11:21
  • You will still need the scan function to be called for each property, you just want to only do something when it's 'entity'. See how you get on with if (k==='entity') within the for loop... – El Ronnoco May 06 '12 at 11:51
  • Ive used the condition if(k==entity), bt it will give me all the values, like count, currrency everything...Hw cme I cn take only values with key "entity"?? – user1371896 May 06 '12 at 13:34
  • Say if (k==='entity') alert( obj.entity ); This should only alert with entity values... – El Ronnoco May 06 '12 at 14:03
  • That will not do the trick.. it wont enter the if I add the condition.. Will edit the part html part in question to show u.. – user1371896 May 06 '12 at 14:24
1
(function recur( obj ) {
    Object.keys( obj ).forEach( function( prop ) {
        // Check if the property is an object
        if ( ({}).toString.apply( prop ) === '[object Object]' ) {
            // If it is, recall this function
            recur( prop );
        }
    } );
} () );

I haven't added your logic, but you get the idea of how to recursively traverse your object.

Florian Margaine
  • 58,730
  • 15
  • 91
  • 116
  • how do I add the value of subobj here for the above example? – user1371896 May 05 '12 at 07:57
  • What? I don't understand your comment. – Florian Margaine May 05 '12 at 07:58
  • Oops, edited my answer correcly. The `subobj` is the property of the object that *is* an object, so you can traverse it too. – Florian Margaine May 05 '12 at 08:04
  • one more doubt, for recursion for this doubt. what If I want to get the value Ford Motor Co, I can do it this way h.Categories.Facets[0].Company[0].entity or I take the value Company using h.Categories.Facets[0].entity and then how do I append the value Company in to "h.Categories.Facets[[0]. '()' .entity" line.. – user1371896 May 05 '12 at 08:09
  • I'm not sure I got you, but are you looking for: `h.Categories.Facets[[0]. '()' .entity = h.Categories.Facets[0].Company[0].entity`? The first part is clearly not good, but I don't know what you mean. – Florian Margaine May 05 '12 at 08:11
  • yes , how do I concatinate the value Company[0] in to h.Categories.Facets[0].''.entity .. Will string concatination wrk?? Like var s=h.Categories.Facets[0].entity; and then h.Categories.Facets[0].s[0].entity or h.Categories.Facets[0].s.entity – user1371896 May 05 '12 at 08:12
  • Oh, I guess you want: `h.Categories.Facets[0].''.entity += Company[0]` – Florian Margaine May 05 '12 at 08:13
  • I'm sorry, but I really don't understand what you mean. – Florian Margaine May 05 '12 at 09:08
1

Say I have a structure like the following:

var aObject = {
    items: [],
    children: {}
}

Children is an associative array that contains more aObjects. So it could look like this:

var aObject = {
    items: [],
    children: {
        "subgroup1": {
            items: [],
            children: {}
        },
        "subgroup2": {
            items: [],
            children: {}
        }
    }
}

I have an item that contains an array of subgroups:

["subgroup1", "subgroup1a"]

Each subgroup is a 'location'. The item needs to be placed at:

aObject.children[array[0]].children[array[1]].items

At each level, we have to check if children[array[i]] exists, and if not, create it. You can't simply write aObject.children[array[0]].children[array[1]].items.push(item) because children[array[0]] might not already exist and we will get an error.

This can be solved using recursion! (AngularJS)

function recursive(aLevel, aItem, aArray, aIndex){
    var lLevel = aLevel;

    // If we have reached the end of the array
    if (aIndex === aArray.length){
        // Insert
        aLevel.items.push(aItem);
    } else {

        // If the subgroup doesn't exist, create it
        if (typeof aLevel.children[aArray[aIndex]] === 'undefined'){
            aLevel.children[aArray[aIndex]] = {
              items: [],
              children: {}
            };
        }

        // Move into
        recursive(aLevel.children[aArray[aIndex]], aItem, aArray, aIndex+1);
    }
}

aObject = {
    items: [],
    children: {},
}

angular.forEach(items, function(item, i){
    var location = item.location;

    if (location.length == 0){
        aObject.items.push(item);
    } else {
        recursive(aObject, item, location, 0);
    }
});

The final aObject would look like this:

var aObject = {
     items: [],
     children: {
        "subgroup1": {
            items: [],
            children: {
                "subgroup1a": {
                    items: [item],
                    children: {}
                }
            }
        },
        "subgroup2": {
            items: [],
            children: {}
        }
    }
}
Sam Whillance
  • 149
  • 1
  • 4
1

Here is a function that i use often. It's easily modifiable to do many recursive tasks. For example if you add a bail flag you can quickly get the stack or add a callback function that makes it even more general. Anyway that's my 2 cents

var recursiveObjMap = (function(){
  var stack = [];
  var result = [];
  // var bail = false;
  return function map(data, key){
    if (!$.isArray(data) && !$.isPlainObject(data) ) { 
      result.push(data);
      return false 
    }

    $.each(data, function(i, v){
      if (key) stack.push(key);
      map(v, i);
      stack.pop();
    });
    return result;
  };
})();

recursiveObjMap({a:'b',c:{d:{e:"f"}}}) // ['b', 'f']
James Harrington
  • 3,138
  • 30
  • 32
0
const obj = [
  {
    count: 1,
    entity: "Company",
    Company: [
      {
        entity: "Ford Motor Co",

        Ford_Motor_Co: [
          {
            count: 1,
            entity: "Ford",
          },
        ],
      },
    ],
  },
  {
    count: 4,
    entity: "Country",
    Country: [
      {
        entity: "Germany",
        Germany: [
          {
            count: 1,
            entity: "Germany",
          },
        ],
        currency: "Euro (EUR)",
      },
      {
        entity: "Italy",
        Italy: [
          {
            count: 1,
            entity: "Italy",
          },
        ],
        currency: "Euro (EUR)",
      },
      {
        entity: "Japan",
        Japan: [
          {
            count: 1,
            entity: "Japan",
          },
        ],
        currency: "Yen (JPY)",
      },
      {
        entity: "South Korea",
        South_Korea: [
          {
            count: 1,
            entity: "South Korea",
          },
        ],
        currency: "Won (KRW)",
      },
    ],
  },
  {
    count: 5,
    entity: "Persons",
    Persons: [
      {
        count: 2,
        entity: "Dodge",
      },
      {
        count: 1,
        entity: "Dodge Avenger",
      },
      {
        count: 1,
        entity: "Major League",
      },
      {
        count: 1,
        entity: "Sterling Heights",
      },
    ],
  },
];
function test(runObj) {
  for (let i in runObj) {
    typeof runObj[i] == "object" ? test(runObj[i]) : console.log(runObj[i]);
  }
}
test(obj);
Steve.g
  • 448
  • 4
  • 5