Return to Snippet

Revision: 61612
at December 29, 2012 08:54 by codernator


Updated Code
/*jslint plusplus: true, vars: true, browser: true, devel: false, maxerr: 5, maxlen: 140 */

//inspired by python list comprehension (x for x in range(10))
function GeneratorModule(boilerMod) {
    "use strict";

    if (!boilerMod || !boilerMod.inherit || !boilerMod.addMethod) {
        throw "boilerMod must be ObjectBoilerPlateModule with methods inherit and addMethod.";
    }
    

    function RangeGenerator(min, max) {
        this.current = min;
        this.max = max;
    }
    RangeGenerator.prototype.next = function () {
        var nn = this.current;
        if (nn === this.max) { return undefined; }
        this.current += 1;
        return nn;
    };

    function InArrayGenerator(list) {
        RangeGenerator.call(this, 0, list.length);
        this.list = list;
    }
    InArrayGenerator.prototype = boilerMod.inherit(RangeGenerator.prototype);
    InArrayGenerator.prototype.next = function () {
        var nn = RangeGenerator.prototype.next.call(this);
        if (nn === undefined) { return undefined; }
        return this.list[nn];
    };

    
    // Generate an array from any generator with optional filtering by 
    // predicate: function (item) { return boolean; } and with optional 
    // morphing of the elements from the generator into another data type. 
    // If !morph, return elements from the generator as is.
    function toList(morph, generator, predicate) {
        if (!predicate) { predicate = function (x) { return true; }; }
        if (!morph) { morph = function (x) { return x; }; }

        var ll = [];
        while (true) {
            var gg = generator.next();
            if (gg === undefined) { break; }
            if (predicate(gg)) { ll.push(morph(gg)); }
        }
        return ll;
    };
    

    this.getGeneratorModuleVersion = function () {
        return 1.0;
    };

    // Iterator for an array.
    this.inArray = function (list) {
        return new InArrayGenerator(list);
    };


    // Generate a sequence 0 <= x < max. Optionally filter sequence
    // by predicate: function (item) { return boolean; }
    boilerMod.addMethod(this, "range", function (max) { return new RangeGenerator(0, max); });
    
    // Generate a sequence min <= x < max. Optionally filter sequence
    // by predicate: function (item) { return boolean; }
    boilerMod.addMethod(this, "range", function (min, max) { return new RangeGenerator(min, max); });
    
    boilerMod.addMethod(this, "toList", function(generator) { return toList(null, generator); });
    boilerMod.addMethod(this, "toList", function(morph, generator) { return toList(morph, generator); });
    boilerMod.addMethod(this, "toList", function(morph, generator, predicate) { return toList(morph, generator, predicate); });
}

Revision: 61611
at December 27, 2012 06:40 by codernator


Updated Code
/*jslint plusplus: true, vars: true, browser: false, devel: false, maxerr: 5, maxlen: 140 */

//inspired by python list comprehension (x for x in range(10))
function GeneratorModule() {
    "use strict";

    function inherit(parentPrototype) {
        function F() {}
        F.prototype = parentPrototype;
        return new F();
    }

    function RangeGenerator(min, max) {
        this.current = min;
        this.max = max;
    }
    RangeGenerator.prototype.next = function () {
        var nn = this.current;
        if (nn === this.max) { return undefined; }
        this.current += 1;
        return nn;
    };

    function InArrayGenerator(list) {
        RangeGenerator.call(this, 0, list.length);
        this.list = list;
    }
    InArrayGenerator.prototype = inherit(RangeGenerator.prototype);
    InArrayGenerator.prototype.next = function () {
        var nn = RangeGenerator.prototype.next.call(this);
        if (nn === undefined) { return undefined; }
        return this.list[nn];
    };


    this.getGeneratorModuleVersion = function () {
        return 1.0;
    };

    // Iterator for an array.
    this.arrayGenerator = function (list) {
        return new InArrayGenerator(list);
    };

    // Generate a sequence min <= x < max. Optionally filter sequence
    // by predicate: function (item) { return boolean; }
    this.rangeGenerator = function (min, max) {
        return new RangeGenerator(min, max);
    };

    // Generate an array from any generator with optional filtering by 
    // predicate: function (item) { return boolean; } and with optional 
    // morphing of the elements from the generator into another data type. 
    // If !morph, return elements from the generator as is.
    this.genList = function (generator, predicate, morph) {
        if (!predicate) { predicate = function (x) { return true; }; }
        if (!morph) { morph = function (x) { return x; }; }

        var ll = [];
        while (true) {
            var gg = generator.next();
            if (gg === undefined) { break; }
            if (predicate(gg)) { ll.push(morph(gg)); }
        }
        return ll;
    };
}

Revision: 61610
at December 27, 2012 06:24 by codernator


Updated Code
/*jslint plusplus: true, vars: true, browser: false, devel: false, maxerr: 5, maxlen: 140 */

//inspired by python list comprehension (x for x in range(10))
function GeneratorModule() {
    "use strict";

    function inherit(parentPrototype) {
        function F() {}
        F.prototype = parentPrototype;
        return new F();
    }

    function RangeGenerator(min, max) {
        this.current = min;
        this.max = max;
    }
    RangeGenerator.prototype.next = function () {
        var nn = this.current;
        if (nn === this.max) { return undefined; }
        this.current += 1;
        return nn;
    };

    function InArrayGenerator(list) {
        RangeGenerator.call(this, 0, list.length);
        this.list = list;
    }
    InArrayGenerator.prototype = inherit(RangeGenerator.prototype);
    InArrayGenerator.prototype.next = function () {
        var nn = RangeGenerator.prototype.next.call(this);
        if (nn === undefined) { return undefined; }
        return this.list[nn];
    };


    this.getGeneratorModuleVersion = function () {
        return 1.0;
    };

    // Iterator for an array.
    this.arrayGenerator = function (list) {
        return new InArrayGenerator(list);
    };

    // Generate a sequence min <= x < max. Optionally filter sequence
    // by predicate: function (item) { return boolean; }
    this.rangeGenerator = function (min, max, predicate) {
        return new RangeGenerator(min, max);
    };

    // Generate an array from any generator with optional filtering by 
    // predicate: function (item) { return boolean; } and with optional 
    // morphing of the elements from the generator into another data type. 
    // If !morph, return elements from the generator as is.
    this.genList = function (generator, predicate, morph) {
        if (!predicate) { predicate = function (x) { return true; }; }
        if (!morph) { morph = function (x) { return x; }; }

        var ll = [];
        while (true) {
            var gg = generator.next();
            if (gg === undefined) { break; }
            if (predicate(gg)) { ll.push(morph(gg)); }
        }
        return ll;
    };
}

Revision: 61609
at December 27, 2012 06:11 by codernator


Initial Code
/*jslint plusplus: true, vars: true, browser: false, devel: false, maxerr: 5, maxlen: 140 */

//inspired by python list comprehension (x for x in range(10))
function GeneratorModule() {
    "use strict";

    function inherit(parentPrototype) {
        function F() {}
        F.prototype = parentPrototype;
        return new F();
    }

    function RangeGenerator(min, max) {
        this.current = min;
        this.max = max;
    }
    RangeGenerator.prototype.next = function () {
        var nn = this.current;
        if (nn === this.max) { return undefined; }
        this.current += 1;
        return nn;
    };

    function FilteredRangeGenerator(min, max, predicate) {
        RangeGenerator.call(this, min, max);
        this.predicate = predicate;
    }
    FilteredRangeGenerator.prototype = inherit(RangeGenerator.prototype);
    FilteredRangeGenerator.prototype.next = function () {
        while (true) {
            var nn = RangeGenerator.prototype.next.call(this);
            if (nn === undefined) { return undefined; }
            if (this.predicate(nn)) { return nn; }
        }
    };

    function InArrayGenerator(list) {
        RangeGenerator.call(this, 0, list.length);
        this.list = list;
    }
    InArrayGenerator.prototype = inherit(RangeGenerator.prototype);
    InArrayGenerator.prototype.next = function () {
        var nn = RangeGenerator.prototype.next.call(this);
        if (nn === undefined) { return undefined; }
        return this.list[nn];
    };

    function InFilteredArrayGenerator(list, predicate) {
        RangeGenerator.call(this, 0, list.length);
        this.list = list;
        this.predicate = predicate;
    }
    InFilteredArrayGenerator.prototype = inherit(RangeGenerator.prototype);
    InFilteredArrayGenerator.prototype.next = function () {
        while (true) {
            var nn = RangeGenerator.prototype.next.call(this);
            if (nn === undefined) { return undefined; }

            var item = this.list[nn];
            if (this.predicate(item)) { return this.list[nn]; }
        }
    };


    this.getGeneratorModuleVersion = function () {
        return 1.0;
    };

    // Iterator for an array with optional filtering by predicate: function (item) { return boolean; }
    this.arrayGenerator = function (list, predicate) {
        if (predicate) { return new InFilteredArrayGenerator(list, predicate); }
        return new InArrayGenerator(list);
    };

    // Generate a sequence min <= x < max. Optionally filter sequence
    // by predicate: function (item) { return boolean; }
    this.rangeGenerator = function (min, max, predicate) {
        if (predicate) { return new FilteredRangeGenerator(min, max, predicate); }
        return new RangeGenerator(min, max);
    };

    // Generate an array from any generator, optionally morphing the elements from the
    // generator into another data type. If !morph, return elements from the generator
    // as is.
    this.genList = function (generator, morph) {
        if (!morph) { morph = function (x) { return x; }; }

        var ll = [];
        while (true) {
            var gg = generator.next();
            if (gg === undefined) { break; }
            ll.push(morph(gg));
        }
        return ll;
    };
}

Initial URL


Initial Description
The inspiration for this module comes from Python's list comprehension: [x for x in range(10)]. The idea is to replace a for-loop with something more condensed. However, since such syntax is completely foreign to Javascript, that operation looks more like: app.genList(app.rangeGenerator(0, 10)).

Requires ObjectBoilerPlateModule.

GeneratorModule comes with four "public" methods:

* getGeneratorModuleVersion - useful to test for existence of module.
* arrayGenerator - iterate over an array, optionally filtering items from the array with a predicate argument.
* rangeGenerator - iterate over a number sequence from min to max.
* genList - create an array using either an arrayGenerator or a rangeGenerator, optionally morphing elements from the generator into a new data type.

This is implemented using module pattern. To inject the functions into the global namespace, simply invoke the GeneratorModule method. Otherwise, the functions can be added to an existing object using GeneratorModule.call([object]).

Examples:

    function test() {
        "use strict";

        function reportNumber(number) {
            return number + " is " + (number % 2 === 0 ? "even" : "odd") + ".";
        }

        function reportLetter(letter) {
            return "The letter is " + letter + ".";
        }

        function isMultipleOf3(number) {
            return number % 3 === 0;
        }

        var app = {};
        ObjectBoilerPlateModule.call(app);
        GeneratorModule.call(app, app);
        console.log(app.toList(app.range(0, 10)));
        // [0,1,2,3,4,5,6,7,8,9]

        console.log(app.toList(reportNumber, app.range(0, 15), isMultipleOf3));
        // ["0 is even.", "3 is odd.", "6 is even.", "9 is odd.", "12 is even."]

        console.log(app.toList(app.inArray(["a", "d", 'q'])));
        // ["a", "d", "q"]

        console.log(app.toList(reportLetter, app.inArray(["a", "d", 'q']), function (x) { return x === "a"; }));
        // ["The letter is a."]
    }

Limitations/Considerations:

* Like Python generators, only 1 iteration will function - the generators do not come with a "reset" method.
* The ArrayGenerator objects hold reference to "list" passed in the constructor. If there is code between creating the generator and invoking it (say with genList), it is possible the contents of "list" will change. (This could be mitigated by having the ArrayGenerator constructor perform a deep copy "list"...)

Initial Title
GeneratorModule: Array Creation Inspired by Python\'s List Comprehension

Initial Tags


Initial Language
JavaScript