Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala's "for comprehension" in Javascript

I've gotten used to Scala's "for" construct and like it a lot. I am now writing some JavaScript code and am using Lodash (basically an extension of Underscore). Is there any way to mimic Scala's "for" comprehension in JavaScript?

My goal is to clean map/reduce code similar to this:

var rawCoordinates = _.map( directionsRoute.legs, function ( leg ) {
   return _.map( leg.steps, function ( step ) {
      return _.map( step.path, function ( latLng ) {
         return [ latLng.lng(), latLng.lat() ];
      } );
   } );
} );
var finalCoordinates = _.flatten( rawCoordinates, true );

In the code, I'm producing an array of coordinates in the format [[coord1,coord2,coord3],[coord4,coord5]], where each coordinate is [39.5, -106.2] (it is an array of the coordinates of each Google Maps directions step).

In Scala, this same thing could be written like this:

val stepCoordinates:List[List[Tuple2[Number,Number]]] = for {
   leg <- legs;
   step <- leg.steps;
   path <- step.path;
   latLng <- path
} yield (latLng.lng(), latLng.lat())

Thanks!

like image 391
Jon Onstott Avatar asked Dec 19 '25 01:12

Jon Onstott


1 Answers

Javascript can't be extended with new keywords or operators, but those are not vital. We can live with usual functions, they may look not that nice, but pretty readable. Below is an example of a function that performs nested for loops.

function deepMap(xs, path, fn) {
    function impl(xs, path, args) {
        var result = new Array(xs.length);
        if (path.length == 0) {
            for (var i = 0; i < xs.length; i++) {
                result[i] = fn.apply(null, args.concat([xs[i]]));
            }
            return result;
        } else {
            for (var i = 0; i < xs.length; i++) {
                result[i] = impl(xs[i][path[0]], path.slice(1), args.concat(xs[i]));
            }
            return result.reduce(function(x, y) {return x.concat(y)}, []);
        }
    }
    return impl(xs, path, []);
}

// for generating lat and long functions
function x(x) {return function() {return x}}

// sample data
var legs = [{
    steps: [{
        path: [{lat: x(1), lng: x(2)}]
    }, {
        path: [{lat: x(2), lng: x(3)}]
    }]
}, {
    steps: [{
        path: [{lat: x(3), lng: x(4)}]
    }, {
        path: [{lat: x(4), lng: x(5)}]
    }]
}];

// prints [ '(1, 2)', '(2, 3)', '(3, 4)', '(4, 5)' ]
console.log(deepMap(legs, ['steps', 'path'], function(leg, step, ll) {
    return "(" + ll.lat() + ", " +  ll.lng() + ")";
}));
like image 70
Yaroslav Avatar answered Dec 20 '25 15:12

Yaroslav



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!