Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loop through JSON - special way

I got a really big nested JSON object like this one:

let myData = {
  character: {
    player: {
      player_1: { type: "player1", test:"A" },
      player_2: { type: "player2", test:"B" },
      player_3: { type: "player3", test:"C" }
    },
    enemy: {
      enemy_walk: {
        enemy_walk_1: { type:"enemy_walkA", test: "..." },
        enemy_walk_2: { type:"enemy_walkB", test: "..." },
        enemy_walk_3: { type:"enemy_walkY", test: "..." }
      }
    }
  },
  blocks: {
    wall: {
      wall_1: { type:"wallA", test: "..." },
      wall_2: { type:"wallB", test: "..." },
    },
    obstacle: {
      brick: {
        brick1: { type:"brickA", test: "..." },
        brick2: { type:"brickC", test: "..." },
      }
    }
  }
}

... and I'd like to loop through every subtree to get a list like this (where the last object of every subtree gets a brand new property called src that represents the path of the object as string:

let result = {
  character: {
    player: {
      player_1: { type: "player1", test:"A", src: "character/player/player_1" },
      player_2: { type: "player2", test:"B", src: "character/player/player_2" },
      player_3: { type: "player3", test:"C", src: "character/player/player_3" }
    },
    enemy: {
      enemy_walk: {
        enemy_walk_1: { type:"enemy_walkA", test: "...", src: "character/enemy/enemy_walk_1" },
        enemy_walk_2: { type:"enemy_walkB", test: "...", src: "character/enemy/enemy_walk_2" },
        enemy_walk_3: { type:"enemy_walkY", test: "...", src: "character/enemy/enemy_walk_3" }
      }
    }
  },
  blocks: {
    wall: {
      wall_1: { type:"wallA", test: "...", src: "blocks/wall/wall_1" },
      wall_2: { type:"wallB", test: "...", src: "blocks/wall/wall_2" },
    },
    obstacle: {
      brick: {
        brick1: { type:"brickA", test: "...", src: "blocks/obstacle/brick/brick1" },
        brick2: { type:"brickC", test: "...", src: "blocks/obstacle/brick/brick2" },
      }
    }
  }
}

Because I do not really got a clue how to start this code is all that I've got so far.

var myData={character:{player:{player_1:{type:"player1",test:"A"},player_2:{type:"player2",test:"B"},player_3:{type:"player3",test:"C"}},enemy:{enemy_walk:{enemy_walk_1:{type:"enemy_walkA",test:"..."},enemy_walk_2:{type:"enemy_walkB",test:"..."},enemy_walk_3:{type:"enemy_walkY",test:"..."}}}},blocks:{wall:{wall_1:{type:"wallA",test:"..."},wall_2:{type:"wallB",test:"..."}},obstacle:{brick:{brick1:{type:"brickA",test:"..."},brick2:{type:"brickC",test:"..."}}}}};

let updateSRC = function(data) {
  let _data = data;
  let recursive = function(_data) {
    for (let key in _data) {
      if (typeof _data[key] == "Object") {
        recursive(_data[key]);
      } else {
         _data[key].src = "?"
      }
    }; recursive(_data)
  }; return _data || null;
}
let result = updateSRC(myData);
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

2 Answers

I would just make a recursive function with a flag (here leaf) to indicate whether the you have any more nested objects.

You can keep track of where you are using a parameter to the function(path). With each recursive step, just add the key to the path.

This will alter the object in place, but it shouldn't be hard to create a new object using the same technique if that's what you're after.

let myData = {character: {player: {player_1: { type: "player1", test:"A" },player_2: { type: "player2", test:"B" },player_3: { type: "player3", test:"C" }},enemy: {enemy_walk: {enemy_walk_1: { type:"enemy_walkA", test: "..." },enemy_walk_2: { type:"enemy_walkB", test: "..." },enemy_walk_3: { type:"enemy_walkY", test: "..." }}}},blocks: {wall: {wall_1: { type:"wallA", test: "..." },wall_2: { type:"wallB", test: "..." },},obstacle: {brick: {brick1: { type:"brickA", test: "..." },brick2: { type:"brickC", test: "..." },}}}}

function walk(obj, path=''){
    let leaf = true
    Object.keys(obj).forEach(key => {
        if (typeof obj[key] === 'object' ){
            walk(obj[key], path +  '/' + key)
            leaf = false // this object has children, so don't add `src` prop
        }
    })
    if (leaf) obj['src'] = path
}

walk(myData)
console.log(myData)
like image 100
Mark Avatar answered May 05 '26 07:05

Mark


You could create a new object and store the path as src if no further nested object is found.

function getUpdate(object, path = []) {
    return Object.assign(...Object
        .entries(object)
        .map(([k, v]) => v && typeof v === 'object'
            ? { [k]: getUpdate(v, path.concat(k)) }
            : { [k]: v, src: path.join('/') }
        )
    );
}

var object = { character: { player: { player_1: { type: "player1", test: "A" }, player_2: { type: "player2", test: "B" }, player_3: { type: "player3", test: "C" } }, enemy: { enemy_walk: { enemy_walk_1: { type: "enemy_walkA", test: "..." }, enemy_walk_2: { type: "enemy_walkB", test: "..." }, enemy_walk_3: { type: "enemy_walkY", test: "..." } } } }, blocks: { wall: { wall_1: { type: "wallA", test: "..." }, wall_2: { type: "wallB", test: "..." } }, obstacle: { brick: { brick1: { type: "brickA", test: "..." }, brick2: { type: "brickC", test: "..." } } } } };

console.log(getUpdate(object));
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 21
Nina Scholz Avatar answered May 05 '26 09:05

Nina Scholz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!