Problem
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.
Solution
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
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);