Подтвердить что ты не робот

Итерация с циклом while вместо цикла

ECMAScript 6 представляет генераторы, итераторы и синтаксический сахар для итерации. Node.JS v0.11.4 с флагами

--harmony --use_strict --harmony_generators

понимает следующий генератор

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

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

Затем я могу напечатать числа Фибоначчи меньше 1000.

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

В этом примере цикл while вместо цикла for был бы более естественным, подобно

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

Можно ли выполнить итерацию итераторов с помощью цикла while вместо цикла for?

4b9b3361

Ответ 1

Что-то подобное вам удовлетворит?

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

плюс, возможно, даже более приятное решение будет выглядеть примерно так:

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

Ответ 2

Есть два возможных способа, по которым я буду говорить об этом, учитывая другие языки, поддерживающие это поведение:

1) Один, используя прокси-серверы Harmony, который позволит вам делать мета-таблицы (вроде как в lua) и допускать ленивые итерации. Это обеспечило бы следующие обозначения:

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

2) Второй, используя функцию take, позволяющую использовать итерабельность с помощью .forEach, как в С# или python. Это позволило бы использовать следующие обозначения:

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

Первый подход - использование прокси-серверов гармонии

Примечание... for of перемещается по объектам. Он не гарантирует порядок. Однако вы можете сделать что-то вроде следующего, чтобы получить понятие ленивой итерации.

Вам нужно запустить node как с флагами --harmony_generators, так и --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
}

Он рассчитает только числа, которые не будут получены, это позволит вам использовать простой цикл for.

Вот как *:

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

(Просто не ожидайте, что это будет очень быстро)

* (используя старую прокси-нотацию, так как новая не поддерживается в node, обновится после ее получения)


Обратите внимание, что в JavaScript, поскольку функции могут иметь внутреннее состояние через замыкания, вам даже не нужен генератор

Второй подход, используя функцию iterator take.

Это то, что вы обычно делаете на таких языках, как С# для этого варианта использования.

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

Затем сделайте что-то вроде

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

Или по счету:

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

Ответ 3

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}

Ответ 4

Да, это можно сделать с помощью обычных методов генератора.

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

Хотя я предпочитаю оператор for...of, который заботится о том, чтобы обрабатывать эти следующие вызовы и иметь дело с StopIteration (если последовательность конечна).