Flattening nested objects with reference to parent object
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
add a comment |
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
add a comment |
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
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
javascript recursion functional-programming
edited Nov 12 at 3:59
Aᴍɪʀ
4,73722745
4,73722745
asked Nov 12 at 3:56
Theepan Thevathasasn
5819
5819
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
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.
add a comment |
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)
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
add a comment |
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.
add a comment |
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.
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
// }
edited Nov 12 at 5:10
answered Nov 12 at 4:59
user633183
67.9k21135175
67.9k21135175
add a comment |
add a comment |
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)
add a comment |
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)
add a comment |
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)
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)
edited Nov 12 at 5:20
answered Nov 12 at 4:01
Mark Meyer
35.7k32957
35.7k32957
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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