Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating with while loop instead of for loop

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?

like image 374
Randomblue Avatar asked Jul 07 '13 13:07

Randomblue


People also ask

Can a while loop be used 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.

Which is better for loop or while loop?

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.

Can while loops and for loops be interchangeable?

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.

Why should you use a while iteration statement instead of a for iteration statement?

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.


2 Answers

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); } 
like image 94
fsw Avatar answered Oct 05 '22 04:10

fsw


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 

First approach - using harmony proxies

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

Second approach, using an iterator 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 
like image 37
Benjamin Gruenbaum Avatar answered Oct 05 '22 04:10

Benjamin Gruenbaum