ECMAScript 6 introduces generators, iterators and syntax sugar for iteration. Node.JS v0.11.4 with the flags
--harmony --use_strict --harmony_generators
understands the following generator
function* fibonacci() { let previous = 0; let current = 1; while(true) { let temp = previous; previous = current; yield current = temp + current; } }
I can then print the Fibonacci numbers less than 1000.
for(let value of fibonacci()) { if(value > 1000) { break; } console.log(value); }
For this example a while
loop instead of a for
loop would be more natural, similar to
while(value of fibonacci() < 1000) { console.log(value); }
Can iteration of iterators be done with a while
loop instead of a for
loop?
Use a for loop when you know the loop should execute n times. Use a while loop for reading a file into a variable. Use a while loop when asking for user input. Use a while loop when the increment value is nonstandard.
Using for: % Time elapsed: 0.0010001659 seconds. Using while: % Time elapsed: 0.026000023 seconds. The main reason that While is much slower is because the while loop checks the condition after each iteration, so if you are going to write this code, just use a for loop instead.
Most Python for loops are easily rewritten as while loops, but not vice-versa. In other programming languages, for and while are almost interchangeable, at least in principle.
The 'for' loop used only when we already knew the number of iterations. The 'while' loop used only when the number of iteration are not exactly known. If the condition is not put up in 'for' loop, then loop iterates infinite times. If the condition is not put up in 'while' loop, it provides compilation error.
You can call a generator step by step using next
function
var sequence = fibonacci(); var value; while ((value = sequence.next()) < 1000) { console.log(value); }
plus, maybe even a nicer solution would be something like:
function* fibonacci(limit){ let previous = 0; let current = 1; while(previous + current < limit) { let temp = previous; previous = current; yield current = temp + current; } } for(let value of fibonacci(1000)) { console.log(value); }
There are two possible ways I'd go on about this, given other languages that support this behavior:
1) One using Harmony proxies, which would let you doing meta-tables (kind of like in lua) and allow for lazy iterables. This would provide fhe following notation:
var arr = ...; // create the resource for(var i=0;arr[i]<1000;i++){ arr[i]; // consume fibonacci numbers }
2) The second using a take
function letting you consume an iterable with .forEach
like in C# or python. Which would allow the following notation:
takeWhile(fibGenerator,(item) => item<1000).forEach(... // consume with predicate
Note... for of
loops through objects. It does not guarantee order at all. You can however do something like the following to get the notion of a lazy iterate.
You have to run node both with the --harmony_generators
and --harmony_proxies
flags:
var arr = ...; // create an array and proxy it, use a generator internally arr[50]; // will calculate the 50th fibonacci element and return it. arr[100];// will calculate the 100th fibonacci element and return it. for(var i=0;arr[i]<1000;i++){ arr[i];//the i-th fibonacci number }
It will only calculate numbers not fetched yet, this will allow you to use a simple for
loop.
Here is how*:
var cache = []; var handler = { get: (function(){ function fibIterator(){ var t=0,a=0,b=0; return function(){ t=a; a+=b; b=t; return a; } } var iterator = fibIterator(); return function (target, fibNumber) { if (name in cache) { return cache[name]; } while(iterator < fibNumber){ // update indexes. } })() } }; var arr = Proxy.create(handler);
(Just don't expect it to be very fast)
*(using old proxy notation, since the new one isn't supported in node yet, will update once it gets support)
Side note, in JavaScript since functions can have internal state through closures, you don't even really need a generator
Take
function.This is what you'd normally do in languages like C# for this use case.
function takeWhile(generating, predicate){ var res = [],last; do{ res.push(last=generating()) }while(predicate(last)); return res; }
Then do something like
var res = takeWhile(fibIterator,function(item){ return item<1000; }); res.forEach(function(){ ...
Or by count:
function take(generating,numToTake){ var res = [],num; do{ res.push(last=generating()) }while(num++ < numToTake); return res; } var res = take(fibIterator,1000);//first 1000 numbers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With