Lesleh
Lesleh

Reputation: 1675

Using ES5 array methods with ES6 generators

What's the correct way of using the new ES5 array functions with ES6 generators? Do I have to explicitly convert the iterable into an array first, or is there a better way? For example:

function* range(low, high) {
    var i = low;
    while(i < high)
        yield i++;
}

// Sum of numbers in range, doesn't work
console.log(range(0, 10).reduce((x,y) => x + y));

Upvotes: 10

Views: 1733

Answers (3)

user663031
user663031

Reputation:

Build the array using Array.from:

console.log(Array.from(range(0, 10)).reduce((x,y) => x + y));

Array.from creates an array from an iterable. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from.

If you want to do the reduce without creating the array, then you'll end up needing to do something like:

var sum = 0;
for (e of range(0, 10)) sum += e;

Upvotes: 5

joews
joews

Reputation: 30330

Generator functions return Iterator objects. The Iterator API does not include higher order Array methods such as map, reduce etc, so you need to build an intermediate Array (or use a library like wu.js).

You can use the spread operator to concisely build an Array from a (finite) iterator:

var sum = [...range(0, 10)].reduce((e, i) => e + i)

Upvotes: 10

Stefano
Stefano

Reputation: 18530

Since Array.from does not work on Chrome at the current time, I needed another way to convert an Iterator into an Array.

(though of course you can shim it with a polyfill)

function iterator2Array(iterator) {
    var result = [];
    for (var item in iterator) {
        result.push(item)
    }
    return result;
}

For similar reasons I add a "toArray" to the prototype of a Map so that I basically convert an iterator into an Array so that you can use its functional-oriented methods; of course each item of the array will be a [key, value] tuple (exactly like in its Map.entries())

if (!Map.prototype.toArray) {
    /**
     * Transforms a map into an Array of 'tuples' [[key, value], ...]
     */
    Map.prototype.toArray = function () {
        var result = [];

        for (var item of this) {
            result.push(item);
        }

        return result;
    }
}

var m = new Map([[0, 0], ['a', 'A']]);
m.toArray()

Then you can use it as an array - remember the [key, value] approach though!

m.toArray().map(
    function(item, index, array) {
        var key = item[0],
        value = item[1];
        console.log(key + ": " + value);
        return value;
});

This will return the values of the map (ok not superuseful of course!)

If you prefer a more standar looking loop:

var i = iterator.entries(),
    result = [],
    value;
while (value = i.next().value) {
    result.push(value);
}

Upvotes: 3

Related Questions