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
?
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);
}
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
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}
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).