1
\$\begingroup\$

I have some JSON where each key stores an array, and I need to combine all those arrays into a single array. My current solution doesn't seem the most friendly to review, but without forEach not able to return a value i'm struggling for a succinct solution.

config = {"levels": {"first": ["a", "b", "c"], "second": ["d", "e", "f"]}};

let combine = [];
Object.keys(config["levels"]).forEach(key=>combine.push(config["levels"][key]));
let levels = [].concat.apply([], combine);
// levels == ["a", "b", "c", "d", "e", "f"]

I never know how children config["levels"] will have there will be so this needs to be dynamic.

\$\endgroup\$
  • \$\begingroup\$ const levels = [].concat.apply([], Object.values(config.levels)); will do it. BTW access object properties is much better using dot notation config.levels.first rather than bracket notation config["levels"]["first"] \$\endgroup\$ – Blindman67 Apr 26 at 18:38
2
\$\begingroup\$

First

but without forEach not able to return a value i'm struggling for a succinct solution.

Addressing this in your post, in the future it may help to know you can use the .map() function, which does return values to an array, unlike forEach()

an example using .map() and what you have:

const config = {"levels": {"first": ["a", "b", "c"], "second": ["d", "e", "f"]}};
const accessor = config.levels

let combine = Object.keys(accessor).map(key=>{return accessor[key]});
let levels = [].concat.apply([], combine);

console.log(levels);
// levels == ["a", "b", "c", "d", "e", "f"]

More Succinct Solution

That said, something like this may be what you're looking for:

const config = {"levels": {"first": ["a", "b", "c"], "second": ["d", "e", "f"]}};
const accessor = config.levels

const combine = Array.prototype.concat(...Object.values(accessor));
console.log(combine)

NOTE 1: Accessor is pulled out in case it needs to change, but is not necessary

\$\endgroup\$
2
\$\begingroup\$

Feedback

Is this code wrapped in a function? I ask because in the first line, i.e.

config = {"levels": {"first": ["a", "b", "c"], "second": ["d", "e", "f"]}};

config is declared outside any brackets and without any keyword like var, let or const, which leads to it being declared globally. It is wise to avoid using global variables unless you are absolutely sure you have no other way to accomplish a task. This avoids scenarios like unintentional re-assignment and tight coupling.

Also, unless a variable is re-assigned, it is wise to use const instead of let. This will prevent unintentional re-assignment. combine could be declared with const since it is never re-assigned.


Whenever an array is declared and then added to via a loop (like forEach) you should consider using the map method instead.

So the following lines

let combine = [];
 Object.keys(config["levels"]).forEach(key=>combine.push(config["levels"][key]));

Could be rewritten like this:

const combine = Object.keys(config["levels"]).map(key=>combine.push(config["levels"][key]));

Perhaps it would be helpful to go through these functional JS exercises, where you practice implementing methods like map, filter, reduce.


As was mentioned in a comment, dot notation can be used instead of bracket notation to accessing object properties. It is "faster to write and clearer to read"1

A Simpler Technique

One simplification would be to use Object.values() to get the nested arrays, and then use Array.flat() to join the arrays together.

const config = {"levels": {"first": ["a", "b", "c"], "second": ["d", "e", "f"]}};
const levels = Object.values(config.levels).flat();
console.log("levels: ", levels);

1https://stackoverflow.com/a/4968448/1575353

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.