jack shephard
jack shephard

Reputation: 13

how to transform nested Object array to an Object with its 'id' as key?

I have some data like these, because the nested object is hard to set state in redux, so I wanna to transform it as an object with id as key.So I can change state easily. I did a whole day search, but did not find a way

// here is the source data
// every object has an id property
// outer object has 2 or 3 levels: continents -> countries || continents -> countires -> regions

    const source = [
      {
        id: 2,
        name: "King",
        continents: [
          {
            id: 12,
            name: "Africa",
            abbr: null,
            countries: [
              {
                id: 13,
                name: "South Africa",
                abbr: "aa.jpg"
              }
            ]
          },
          {
            id: 5,
            name: "European",
            abbr: null,
            countries: [
              {
                id: 7,
                name: "France",
                abbr: "fg.jpg"
              }
            ]
          },
          {
            id: 6,
            name: "North America",
            abbr: null,
            countries: [
              {
                id: 8,
                name: "Denmark",
                abbr: "gg.jpg"
              }
            ]
          }
        ]
      },
      {
        id: 1,
        name: "Elite",
        continents: [
          {
            id: 2,
            name: "South America",
            abbr: null,
            countries: [
              {
                id: 4,
                name: "Brazal",
                abbr: "bx.jpg"
              }
            ]
          },
          {
            id: 5,
            name: "European",
            abbr: null,
            countries: [
              {
                id: 9,
                name: "England",
                abbr: "yg.jpg",
                regions: [
                  {
                    id: 1,
                    name: "England-1",
                    abbr: null,
                    
                  },
                  {
                    id: 10,
                    name: "England-2",
                    abbr: null,
                    
                  }
                ]
              }
            ]
          }
        ]
      }
    ];

as you can see, every Object has an id field.I wanna extract every id as key, output below:

// output
{
  2: {
    id: 2,
    name: "King",
    continents: {
      12: {
        id: 12,
        name: "Africa",
        countries: {
          13: {
            id: 13,
            name: "South Africa"
          }
        }
      },
      6: {
        id: 6,
        name: "North America",
        countries: {
          8: {
            id: 8,
            name: "Denmark"
          }
        }
      },
      5: {
        id: 5,
        name: "European",
        countries: {
          7: {
            id: 7,
            name: "France"
          }
        }
      }
    }
  },
  1: {
    id: 1,
    name: "Elite",
    continents: {
      2: {
        id: 2,
        name: "South America",
        countries: {
          4: {
            id: 4,
            name: "Brazal"
          }
        }
      },
      5: {
        id: 5,
        name: "European",
        countries: {
          9: {
            id: 9,
            name: "England",
            regions: {
              1: {
                id: 1,
                name: "England-1"
              },
              2: {
                id: 2,
                name: "England-2"
              }
            }
          }
        }
      }
    }
  }
}

I think I should use recursive or something, I even try with ramda.js,but still got no luck!

Upvotes: 0

Views: 108

Answers (1)

Jonas Wilms
Jonas Wilms

Reputation: 138257

Create a function to turn arrays into lookup objects:

  const toLookup = (array, key) => array.reduce((obj, el) => (obj[ el[key] ] = el, obj), {});

Then another one to traverse and map all nested properties:

 function traverse (mapper, root) {
   const result = {};
   for(let [k, v] of Object.entries(root)) {
     v = mapper(v, k);
     if(typeof v === "object" && !Array.isArray(v) && v !== null)
       v = traverse(mapper, v);
     result[k] = v;
  }
  return result;
}

Now use that and turn every array into a lookup object:

 const result = traverse(
  it => Array.isArray(it) ? toLookup(it, "id") : it,
  toLookup(source, "id")
);

Upvotes: 2

Related Questions