Itération avec la boucle while au lieu de la boucle for

ECMAScript 6 introduit des générateurs, des itérateurs et du sucre de syntaxe pour l'itération. Nœud.JS v0. 11. 4 avec les drapeaux

--harmony --use_strict --harmony_generators

Comprend le générateur suivant

function* fibonacci() {
  let previous = 0;
  let current = 1;

  while(true) {
    let temp = previous;
    previous = current;
    yield current = temp + current;
  }
}

Je peux alors imprimer les nombres de Fibonacci inférieurs à 1000.

for(let value of fibonacci()) {
    if(value > 1000) { break; }
    console.log(value);
}

Pour cet exemple, une boucle while au lieu d'une boucle for serait plus naturelle, similaire à

while(value of fibonacci() < 1000) {
    console.log(value);
}

L'itération des itérateurs peut-elle être effectuée avec une boucle while au lieu d'une boucle for?

40
demandé sur Randomblue 2013-07-07 17:49:26

4 réponses

Quelque chose comme ça vous satisferait?

var sequence = fibonacci();
var value;
while ((value = sequence.next()) < 1000) {
    console.log(value);
}

De plus, peut-être même une solution plus agréable serait quelque chose comme:

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);
}
13
répondu fsw 2013-07-07 14:39:44

Il y a deux façons possibles d'aller à ce sujet, étant donné d'autres langues qui supportent ce comportement:

1) on utilise des proxies Harmony, ce qui vous permettrait de faire des méta-tables (un peu comme dans lua) et de permettre des itérables paresseux. Cela fournirait la notation suivante:

var arr = ...; // create the resource
for(var i=0;arr[i]<1000;i++){
    arr[i]; // consume fibonacci numbers
}

2) la seconde utilisant une fonction take vous permettant de consommer un itérable avec .forEach comme dans C # ou python . Ce qui permettrait ce qui suit notation:

 takeWhile(fibGenerator,(item) => item<1000).forEach(... // consume with predicate

Première approche-utilisation de proxies harmony

Remarque... for of boucle les objets. Il ne garantit pas l'ordre du tout. Vous pouvez cependant faire quelque chose comme ce qui suit pour obtenir la notion d'une itération paresseuse.

Vous devez exécuter le nœud à la fois avec les drapeaux --harmony_generators et --harmony_proxies:

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
}

Il ne calculera que les nombres non encore récupérés, cela vous permettra d'utiliser une simple boucle for.

Voici comment*:

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);

(Ne vous attendez pas à ce que ce soit très rapide)

*(en utilisant l'ancienne notation proxy, puisque la nouvelle n'est pas encore prise en charge dans le nœud, elle sera mise à jour une fois prise en charge)


Note latérale, en JavaScript puisque les fonctions peuvent avoir un état interne grâce à des fermetures, vous n'avez même pas vraiment besoin d'un générateur

Deuxième approche, en utilisant une fonction itérateur Take.

C'est ce que vous feriez normalement dans des langages comme C# pour ce cas d'utilisation.

function takeWhile(generating, predicate){
    var res = [],last;
    do{
        res.push(last=generating())
    }while(predicate(last));
    return res;
} 

Alors faites quelque chose comme

var res = takeWhile(fibIterator,function(item){
    return item<1000;
});
res.forEach(function(){ ...

Ou par nombre:

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
7
répondu Benjamin Gruenbaum 2013-07-07 14:41:52

function *bar(){
  yield 1;
  yield 2;
  yield 3;
  return 4;
}

var value,
  g = bar();

while((value = g.next()).value){
  console.log(value);
}
//Object {value: 1, done: false}
//Object {value: 2, done: false}
//Object {value: 3, done: false}
//Object {value: 4, done: true}
1
répondu bchen 2018-01-31 13:50:45

Oui, il est possible de le faire en utilisant les méthodes de générateur régulières.

var fib = fibonacci(), value;
while( (value = fib.next()) < 1000 ) {
    console.log(value);
}

Bien que je semble préférer l'instruction for...of qui prend soin de gérer ces prochains appels et de traiter StopIteration (si la séquence est finie).

0
répondu Mattias Buelens 2013-07-07 14:05:32