I have a function which converts a set of Javascript objects into a map. However, I get an object which cannot be navigated for its values; Here is the sample json
{ "products":{ "lemonade":{ "product-type":"beverage", "product-details":{ "calories":"129", "product-categories":[ 222, 444 ] } }, "limeade":{ "product-type":"beverage", "product-details":{ "calories":"220", "product-categories":[ 222, 444 ], "salesIndex":{ "percentage":1101, "demographics":"region-1" } } } } }
Here is my function to convert to a map:
function objectToMap(o) { const m = new Map(); console.log(`Processing for fragment ${fragment}`); for (const k of Object.keys(o)) { if (o[k] instanceof Object) { console.log(`Key is ${k} and object is ${JSON.stringify(o[k])}`); m.set(k, objectToMap(o[k])); } else { console.log(`Not an object ::Key is ${k} and object is ${JSON.stringify(o[k])}`); m.set(k, o[k]); } } return m; }
Here is how I try to use and print the map:
const m1 = objectToMap(obj.products); printMap(m1); function printMap(map) { for (const k of map.keys()) { console.log(`Current key is ${k} and value is ${map.get(k)}`); if (map.get(k) instanceof Map) { printMap(map.get(k)); } else { console.log(`No it is not a map :: Key is ${k} and value is ${map.get(k)}`); } } }
However, I get for some this key, salesIndex, [object Map], why are the key, values not printed?
Advertisement
Answer
why are the key, values not printed?
They are printed, but the primitive values only get printed (later) when the object is passed to the recursive call, and there the else
block is executed, i.e. when you arrive at the base case of the recursion.
Your code is fine, but you should avoid printing the value when you’re not yet at that base case, as that value still needs to be passed to the recursive call, which will take care of printing the deeper key/values.
I would suggest:
- To only print the key (not the value) when the value is still an object
- Print with indentation so it is much clearer what the structure is of the data
- In
objectToMap
, supportnull
values: for that you need to change the is-object test.
That’s the most important, but I’d also:
- In
objectToMap
, useObject.entries
instead ofObject.keys
so you get both the key and the value as your loop variables - Similarly, in
printMap
, usemap.entries
instead ofmap.values
so you get both the key and the value as your loop variables - In
objectToMap
, as you callmap.set()
in bothif
andelse
cases, start with the call, and differentiate the argument with a conditional (ternary) operator
So like this:
// For the purpose of this answer, console.log removed from this function: function objectToMap(o) { const m = new Map(); for (const [k, v] of Object.entries(o)) { // Get both key and value // Use conditional operator and better way to check for objects: m.set(k, Object(v) === v ? objectToMap(v) : v); } return m; } // Extra argument for printing with indentation function printMap(map, tab="") { for (const [k, v] of map.entries()) { // Don't print here yet... if (v instanceof Map) { console.log(`${tab}${k}:`); // Only print the key here... printMap(v, tab + " "); // ...as recursion will take care of the value(s) } else { console.log(`${tab}${k} = ${v}`); } } } // demo const obj = {"products":{"lemonade":{"product-type":"beverage","product-details":{"calories":"129","product-categories":[222,444]}},"limeade":{"product-type":"beverage","product-details":{"calories":"220","product-categories":[222,444],"salesIndex":{"percentage":1101,"demographics":"region-1"}}}}}; const m = objectToMap(obj.products); printMap(m);