I'm currently playing with D3.js.
While doing so I use this JSON-file as a data source: http://codepen.io/chriscoyier/pen/taqCe
Example of the structure:
{
"fathers" : [
{
"id" : 0,
"married" : false,
"name" : "Robert Wilson",
"sons" : null,
"daughters" : [
{
"age" : 21,
"name" : "Nancy"
},
{
"age" : 30,
"name" : "Amy"
}
]
},
{
"id" : 1,
"married" : true,
"name" : "Robert Thomas",
"sons" : null,
"daughters" : [
{
"age" : 22,
"name" : "Melissa"
},
{
"age" : 6,
"name" : "Susan"
}
]
},
...
]
}
I'm only interested in "daughters". I have mapped the objects into a flat array structure. The code I used:
var fathers = data.fathers,
separator = '-------------------',
persons = []; // collector array
// Filling the collector array with the
// desired data.
fathers.forEach(function(value) {
value['daughters'].forEach(function(value) {
persons.push(value);
});
});
It works fine. My complete code here: http://codepen.io/mizech/pen/WrNzJe
But I wonder: Aren't there better ways (in native JavaScript, no frameworks) then iterating?
Would be pleased if anyone has an idea and would share it.
2 Answers 2
What you are effectivelly doing is reducing your original data-structure to the data you actually need. Effectively, you would not do much different:
var persons = data.fathers.reduce( function( prev, elem ) {
prev.push.apply( prev, elem.daughters );
return prev;
}, [] );
You still loop through all values, and "push" all daughters into the Array you are building.
One change I would suggest is to not use the construction
var a = something,
b = something else,
c = "yellow";
This is prone to errors. If you forget a comma, or type a semicolon instead of a comma, you drop some of your variables into the global namespace.
Just type "var" for every variable:
var a = something;
var b = something else;
var c = "yellow";
-
\$\begingroup\$ Considering the declarations: You absolutely right. Haven't thought that way. Thanks for the tips. \$\endgroup\$x32– x322015年12月05日 10:49:03 +00:00Commented Dec 5, 2015 at 10:49
The operation you want is called flatMap
, SelectMany
, or concatMap
(I might have missed a few names.)
Map a function over a collection and flatten the result by one-level
As far as I'm aware, this isn't provided out-of-the-box but I found an implementation here:
Array.prototype.flatMap = function(lambda) {
return Array.prototype.concat.apply([], this.map(lambda));
};
Then you can just write
var persons = data.fathers.flatMap(function(father) { return father.daughters; });
Or if you can use arrow functions,
var persons = data.fathers.flatMap(father => father.daughters);