Итерация с циклом 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
?
Ответы
Ответ 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
(если последовательность конечна).