Flattening nested objects with reference to parent object












0














I would like to flatten the below



let o = {
name: "John",
school: {
name: "Phillps",
}
};


to:



{
name: "John",
schoolName: "Phillps"
}


My code looks like this



f= Object.assign({}, ..._flatten(o));

function _flatten(o) {
return .concat(
...Object.keys(o).map(k =>
typeof o[k] === "object" ? _flatten(o[k]) : { [k]: o[k] }
)
);
}


This produces



{  
name: "Phillps"
}


As you can see, it cannot deal with conflict in the property names in nested object. I.e. name of the student is overwritten my the name of the school. Is it possible to modify the code so the deep properties are prefixed with their parent object names?










share|improve this question





























    0














    I would like to flatten the below



    let o = {
    name: "John",
    school: {
    name: "Phillps",
    }
    };


    to:



    {
    name: "John",
    schoolName: "Phillps"
    }


    My code looks like this



    f= Object.assign({}, ..._flatten(o));

    function _flatten(o) {
    return .concat(
    ...Object.keys(o).map(k =>
    typeof o[k] === "object" ? _flatten(o[k]) : { [k]: o[k] }
    )
    );
    }


    This produces



    {  
    name: "Phillps"
    }


    As you can see, it cannot deal with conflict in the property names in nested object. I.e. name of the student is overwritten my the name of the school. Is it possible to modify the code so the deep properties are prefixed with their parent object names?










    share|improve this question



























      0












      0








      0







      I would like to flatten the below



      let o = {
      name: "John",
      school: {
      name: "Phillps",
      }
      };


      to:



      {
      name: "John",
      schoolName: "Phillps"
      }


      My code looks like this



      f= Object.assign({}, ..._flatten(o));

      function _flatten(o) {
      return .concat(
      ...Object.keys(o).map(k =>
      typeof o[k] === "object" ? _flatten(o[k]) : { [k]: o[k] }
      )
      );
      }


      This produces



      {  
      name: "Phillps"
      }


      As you can see, it cannot deal with conflict in the property names in nested object. I.e. name of the student is overwritten my the name of the school. Is it possible to modify the code so the deep properties are prefixed with their parent object names?










      share|improve this question















      I would like to flatten the below



      let o = {
      name: "John",
      school: {
      name: "Phillps",
      }
      };


      to:



      {
      name: "John",
      schoolName: "Phillps"
      }


      My code looks like this



      f= Object.assign({}, ..._flatten(o));

      function _flatten(o) {
      return .concat(
      ...Object.keys(o).map(k =>
      typeof o[k] === "object" ? _flatten(o[k]) : { [k]: o[k] }
      )
      );
      }


      This produces



      {  
      name: "Phillps"
      }


      As you can see, it cannot deal with conflict in the property names in nested object. I.e. name of the student is overwritten my the name of the school. Is it possible to modify the code so the deep properties are prefixed with their parent object names?







      javascript recursion functional-programming






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 12 at 3:59









      Aᴍɪʀ

      4,73722745




      4,73722745










      asked Nov 12 at 3:56









      Theepan Thevathasasn

      5819




      5819
























          2 Answers
          2






          active

          oldest

          votes


















          1














          You could use Object.entries, Array.prototype.flatMap and Object.fromEntries






          const upperFirst = (str = "") =>
          str[0] .toUpperCase () + str.substr(1)

          const camelCase = ([ first = "", ...rest ]) =>
          first + rest .map (upperFirst) .join ('')

          const append = (xs, x) =>
          xs .concat ([ x ])

          const flatten = (o = {}) =>
          { const loop = (o, path) =>
          Object (o) === o
          ? Object .entries (o) .flatMap
          ( ([ k, v ]) =>
          loop
          ( v
          , append (path, k)
          )
          )
          : [ [ camelCase (path), o ] ]
          return Object .fromEntries (loop (o, ))
          }

          console.log
          ( flatten
          ( { name: "John"
          , school:
          { name: "Phillips"
          , district: { zone: 1 }
          }
          }
          )
          )

          // { "name": "John"
          // , "schoolName": "Phillips"
          // , "schoolDistrictZone": 1
          // }





          flatMap eagerly evaluates the input and creates some intermediate values before flatten can return. Because Object.fromEntries accepts any iterable, we would probably be better off writing loop with a generator



          const flatten = (o = {}) =>
          { const loop = function* (o, path)
          { if (Object (o) === o)
          for (const [ k, v ] of Object .entries (o))
          yield* loop
          ( v
          , append (path, k)
          )
          else
          yield [ camelCase (path), o ]
          }
          return Object .fromEntries (loop (o, ))
          }


          Re-run the program and you will see the exact same output. Also worth mentioning is the structural similarity between the two programs.






          share|improve this answer































            0














            You can use your same code and just pass a prefix as an argument to _flatten(). As you recourse concat the prefix with the current parent key. This will continue adding prefixes as the nesting gets deeper:






            function _flatten(o, prefix="") {
            return .concat(
            ...Object.keys(o).map(k =>
            typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
            )
            );
            }

            let o = {
            name: "John",
            school: {
            name: "Phillps",
            }
            };

            f= Object.assign({}, ..._flatten(o));

            console.log(f)





            Additionally, you can simply the code a bit using reduce() and Object.assign rather than creating arrays with .concact()






            function _flatten(o, prefix = "") {
            return Object.keys(o).reduce((obj, k) =>
            Object.assign(obj, typeof o[k] === "object"
            ? _flatten(o[k], prefix + k)
            : { [prefix + k]: o[k]})
            , {})
            }

            let o = {
            name: "John",
            school: {
            name: "Phillps",
            }
            };

            f = _flatten(o);

            console.log(f)








            share|improve this answer























              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255765%2fflattening-nested-objects-with-reference-to-parent-object%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              1














              You could use Object.entries, Array.prototype.flatMap and Object.fromEntries






              const upperFirst = (str = "") =>
              str[0] .toUpperCase () + str.substr(1)

              const camelCase = ([ first = "", ...rest ]) =>
              first + rest .map (upperFirst) .join ('')

              const append = (xs, x) =>
              xs .concat ([ x ])

              const flatten = (o = {}) =>
              { const loop = (o, path) =>
              Object (o) === o
              ? Object .entries (o) .flatMap
              ( ([ k, v ]) =>
              loop
              ( v
              , append (path, k)
              )
              )
              : [ [ camelCase (path), o ] ]
              return Object .fromEntries (loop (o, ))
              }

              console.log
              ( flatten
              ( { name: "John"
              , school:
              { name: "Phillips"
              , district: { zone: 1 }
              }
              }
              )
              )

              // { "name": "John"
              // , "schoolName": "Phillips"
              // , "schoolDistrictZone": 1
              // }





              flatMap eagerly evaluates the input and creates some intermediate values before flatten can return. Because Object.fromEntries accepts any iterable, we would probably be better off writing loop with a generator



              const flatten = (o = {}) =>
              { const loop = function* (o, path)
              { if (Object (o) === o)
              for (const [ k, v ] of Object .entries (o))
              yield* loop
              ( v
              , append (path, k)
              )
              else
              yield [ camelCase (path), o ]
              }
              return Object .fromEntries (loop (o, ))
              }


              Re-run the program and you will see the exact same output. Also worth mentioning is the structural similarity between the two programs.






              share|improve this answer




























                1














                You could use Object.entries, Array.prototype.flatMap and Object.fromEntries






                const upperFirst = (str = "") =>
                str[0] .toUpperCase () + str.substr(1)

                const camelCase = ([ first = "", ...rest ]) =>
                first + rest .map (upperFirst) .join ('')

                const append = (xs, x) =>
                xs .concat ([ x ])

                const flatten = (o = {}) =>
                { const loop = (o, path) =>
                Object (o) === o
                ? Object .entries (o) .flatMap
                ( ([ k, v ]) =>
                loop
                ( v
                , append (path, k)
                )
                )
                : [ [ camelCase (path), o ] ]
                return Object .fromEntries (loop (o, ))
                }

                console.log
                ( flatten
                ( { name: "John"
                , school:
                { name: "Phillips"
                , district: { zone: 1 }
                }
                }
                )
                )

                // { "name": "John"
                // , "schoolName": "Phillips"
                // , "schoolDistrictZone": 1
                // }





                flatMap eagerly evaluates the input and creates some intermediate values before flatten can return. Because Object.fromEntries accepts any iterable, we would probably be better off writing loop with a generator



                const flatten = (o = {}) =>
                { const loop = function* (o, path)
                { if (Object (o) === o)
                for (const [ k, v ] of Object .entries (o))
                yield* loop
                ( v
                , append (path, k)
                )
                else
                yield [ camelCase (path), o ]
                }
                return Object .fromEntries (loop (o, ))
                }


                Re-run the program and you will see the exact same output. Also worth mentioning is the structural similarity between the two programs.






                share|improve this answer


























                  1












                  1








                  1






                  You could use Object.entries, Array.prototype.flatMap and Object.fromEntries






                  const upperFirst = (str = "") =>
                  str[0] .toUpperCase () + str.substr(1)

                  const camelCase = ([ first = "", ...rest ]) =>
                  first + rest .map (upperFirst) .join ('')

                  const append = (xs, x) =>
                  xs .concat ([ x ])

                  const flatten = (o = {}) =>
                  { const loop = (o, path) =>
                  Object (o) === o
                  ? Object .entries (o) .flatMap
                  ( ([ k, v ]) =>
                  loop
                  ( v
                  , append (path, k)
                  )
                  )
                  : [ [ camelCase (path), o ] ]
                  return Object .fromEntries (loop (o, ))
                  }

                  console.log
                  ( flatten
                  ( { name: "John"
                  , school:
                  { name: "Phillips"
                  , district: { zone: 1 }
                  }
                  }
                  )
                  )

                  // { "name": "John"
                  // , "schoolName": "Phillips"
                  // , "schoolDistrictZone": 1
                  // }





                  flatMap eagerly evaluates the input and creates some intermediate values before flatten can return. Because Object.fromEntries accepts any iterable, we would probably be better off writing loop with a generator



                  const flatten = (o = {}) =>
                  { const loop = function* (o, path)
                  { if (Object (o) === o)
                  for (const [ k, v ] of Object .entries (o))
                  yield* loop
                  ( v
                  , append (path, k)
                  )
                  else
                  yield [ camelCase (path), o ]
                  }
                  return Object .fromEntries (loop (o, ))
                  }


                  Re-run the program and you will see the exact same output. Also worth mentioning is the structural similarity between the two programs.






                  share|improve this answer














                  You could use Object.entries, Array.prototype.flatMap and Object.fromEntries






                  const upperFirst = (str = "") =>
                  str[0] .toUpperCase () + str.substr(1)

                  const camelCase = ([ first = "", ...rest ]) =>
                  first + rest .map (upperFirst) .join ('')

                  const append = (xs, x) =>
                  xs .concat ([ x ])

                  const flatten = (o = {}) =>
                  { const loop = (o, path) =>
                  Object (o) === o
                  ? Object .entries (o) .flatMap
                  ( ([ k, v ]) =>
                  loop
                  ( v
                  , append (path, k)
                  )
                  )
                  : [ [ camelCase (path), o ] ]
                  return Object .fromEntries (loop (o, ))
                  }

                  console.log
                  ( flatten
                  ( { name: "John"
                  , school:
                  { name: "Phillips"
                  , district: { zone: 1 }
                  }
                  }
                  )
                  )

                  // { "name": "John"
                  // , "schoolName": "Phillips"
                  // , "schoolDistrictZone": 1
                  // }





                  flatMap eagerly evaluates the input and creates some intermediate values before flatten can return. Because Object.fromEntries accepts any iterable, we would probably be better off writing loop with a generator



                  const flatten = (o = {}) =>
                  { const loop = function* (o, path)
                  { if (Object (o) === o)
                  for (const [ k, v ] of Object .entries (o))
                  yield* loop
                  ( v
                  , append (path, k)
                  )
                  else
                  yield [ camelCase (path), o ]
                  }
                  return Object .fromEntries (loop (o, ))
                  }


                  Re-run the program and you will see the exact same output. Also worth mentioning is the structural similarity between the two programs.






                  const upperFirst = (str = "") =>
                  str[0] .toUpperCase () + str.substr(1)

                  const camelCase = ([ first = "", ...rest ]) =>
                  first + rest .map (upperFirst) .join ('')

                  const append = (xs, x) =>
                  xs .concat ([ x ])

                  const flatten = (o = {}) =>
                  { const loop = (o, path) =>
                  Object (o) === o
                  ? Object .entries (o) .flatMap
                  ( ([ k, v ]) =>
                  loop
                  ( v
                  , append (path, k)
                  )
                  )
                  : [ [ camelCase (path), o ] ]
                  return Object .fromEntries (loop (o, ))
                  }

                  console.log
                  ( flatten
                  ( { name: "John"
                  , school:
                  { name: "Phillips"
                  , district: { zone: 1 }
                  }
                  }
                  )
                  )

                  // { "name": "John"
                  // , "schoolName": "Phillips"
                  // , "schoolDistrictZone": 1
                  // }





                  const upperFirst = (str = "") =>
                  str[0] .toUpperCase () + str.substr(1)

                  const camelCase = ([ first = "", ...rest ]) =>
                  first + rest .map (upperFirst) .join ('')

                  const append = (xs, x) =>
                  xs .concat ([ x ])

                  const flatten = (o = {}) =>
                  { const loop = (o, path) =>
                  Object (o) === o
                  ? Object .entries (o) .flatMap
                  ( ([ k, v ]) =>
                  loop
                  ( v
                  , append (path, k)
                  )
                  )
                  : [ [ camelCase (path), o ] ]
                  return Object .fromEntries (loop (o, ))
                  }

                  console.log
                  ( flatten
                  ( { name: "John"
                  , school:
                  { name: "Phillips"
                  , district: { zone: 1 }
                  }
                  }
                  )
                  )

                  // { "name": "John"
                  // , "schoolName": "Phillips"
                  // , "schoolDistrictZone": 1
                  // }






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 12 at 5:10

























                  answered Nov 12 at 4:59









                  user633183

                  67.9k21135175




                  67.9k21135175

























                      0














                      You can use your same code and just pass a prefix as an argument to _flatten(). As you recourse concat the prefix with the current parent key. This will continue adding prefixes as the nesting gets deeper:






                      function _flatten(o, prefix="") {
                      return .concat(
                      ...Object.keys(o).map(k =>
                      typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
                      )
                      );
                      }

                      let o = {
                      name: "John",
                      school: {
                      name: "Phillps",
                      }
                      };

                      f= Object.assign({}, ..._flatten(o));

                      console.log(f)





                      Additionally, you can simply the code a bit using reduce() and Object.assign rather than creating arrays with .concact()






                      function _flatten(o, prefix = "") {
                      return Object.keys(o).reduce((obj, k) =>
                      Object.assign(obj, typeof o[k] === "object"
                      ? _flatten(o[k], prefix + k)
                      : { [prefix + k]: o[k]})
                      , {})
                      }

                      let o = {
                      name: "John",
                      school: {
                      name: "Phillps",
                      }
                      };

                      f = _flatten(o);

                      console.log(f)








                      share|improve this answer




























                        0














                        You can use your same code and just pass a prefix as an argument to _flatten(). As you recourse concat the prefix with the current parent key. This will continue adding prefixes as the nesting gets deeper:






                        function _flatten(o, prefix="") {
                        return .concat(
                        ...Object.keys(o).map(k =>
                        typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
                        )
                        );
                        }

                        let o = {
                        name: "John",
                        school: {
                        name: "Phillps",
                        }
                        };

                        f= Object.assign({}, ..._flatten(o));

                        console.log(f)





                        Additionally, you can simply the code a bit using reduce() and Object.assign rather than creating arrays with .concact()






                        function _flatten(o, prefix = "") {
                        return Object.keys(o).reduce((obj, k) =>
                        Object.assign(obj, typeof o[k] === "object"
                        ? _flatten(o[k], prefix + k)
                        : { [prefix + k]: o[k]})
                        , {})
                        }

                        let o = {
                        name: "John",
                        school: {
                        name: "Phillps",
                        }
                        };

                        f = _flatten(o);

                        console.log(f)








                        share|improve this answer


























                          0












                          0








                          0






                          You can use your same code and just pass a prefix as an argument to _flatten(). As you recourse concat the prefix with the current parent key. This will continue adding prefixes as the nesting gets deeper:






                          function _flatten(o, prefix="") {
                          return .concat(
                          ...Object.keys(o).map(k =>
                          typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
                          )
                          );
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f= Object.assign({}, ..._flatten(o));

                          console.log(f)





                          Additionally, you can simply the code a bit using reduce() and Object.assign rather than creating arrays with .concact()






                          function _flatten(o, prefix = "") {
                          return Object.keys(o).reduce((obj, k) =>
                          Object.assign(obj, typeof o[k] === "object"
                          ? _flatten(o[k], prefix + k)
                          : { [prefix + k]: o[k]})
                          , {})
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f = _flatten(o);

                          console.log(f)








                          share|improve this answer














                          You can use your same code and just pass a prefix as an argument to _flatten(). As you recourse concat the prefix with the current parent key. This will continue adding prefixes as the nesting gets deeper:






                          function _flatten(o, prefix="") {
                          return .concat(
                          ...Object.keys(o).map(k =>
                          typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
                          )
                          );
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f= Object.assign({}, ..._flatten(o));

                          console.log(f)





                          Additionally, you can simply the code a bit using reduce() and Object.assign rather than creating arrays with .concact()






                          function _flatten(o, prefix = "") {
                          return Object.keys(o).reduce((obj, k) =>
                          Object.assign(obj, typeof o[k] === "object"
                          ? _flatten(o[k], prefix + k)
                          : { [prefix + k]: o[k]})
                          , {})
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f = _flatten(o);

                          console.log(f)








                          function _flatten(o, prefix="") {
                          return .concat(
                          ...Object.keys(o).map(k =>
                          typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
                          )
                          );
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f= Object.assign({}, ..._flatten(o));

                          console.log(f)





                          function _flatten(o, prefix="") {
                          return .concat(
                          ...Object.keys(o).map(k =>
                          typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
                          )
                          );
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f= Object.assign({}, ..._flatten(o));

                          console.log(f)





                          function _flatten(o, prefix = "") {
                          return Object.keys(o).reduce((obj, k) =>
                          Object.assign(obj, typeof o[k] === "object"
                          ? _flatten(o[k], prefix + k)
                          : { [prefix + k]: o[k]})
                          , {})
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f = _flatten(o);

                          console.log(f)





                          function _flatten(o, prefix = "") {
                          return Object.keys(o).reduce((obj, k) =>
                          Object.assign(obj, typeof o[k] === "object"
                          ? _flatten(o[k], prefix + k)
                          : { [prefix + k]: o[k]})
                          , {})
                          }

                          let o = {
                          name: "John",
                          school: {
                          name: "Phillps",
                          }
                          };

                          f = _flatten(o);

                          console.log(f)






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Nov 12 at 5:20

























                          answered Nov 12 at 4:01









                          Mark Meyer

                          35.7k32957




                          35.7k32957






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255765%2fflattening-nested-objects-with-reference-to-parent-object%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              這個網誌中的熱門文章

                              Xamarin.form Move up view when keyboard appear

                              Post-Redirect-Get with Spring WebFlux and Thymeleaf

                              Anylogic : not able to use stopDelay()