4
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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";
\$\endgroup\$
1
  • \$\begingroup\$ Considering the declarations: You absolutely right. Haven't thought that way. Thanks for the tips. \$\endgroup\$
    – x32
    Dec 5 '15 at 10:49
3
\$\begingroup\$

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);
\$\endgroup\$
0

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.