2016-12-28 2 views
3

Учитывая следующее. Я хочу лениво применить transform к каждому члену итерабельного, возвращенному с Object.keys.Составные генераторы

Как это сделать?

function* numbers(upto, transform) { 
    yield* Object.keys([...Array(upto)]); // How can `transform` be applied here lazily? 
} 

function timesTwo(n) { 
    return n*2; 
} 

var generator = numbers(31, timesTwo) 

for(var i of generator) { 
    console.log(i); // 0 2 4 6 8... 60 
} 
+0

Этот параметр 'transform' делает это казаться, что вы счастливы, что преобразование перешли в «числа», а не составляли их извне, верно? –

+0

Да. Открыто для лучших способов, хотя – Ben

+1

пытался создать простой пример, но, возможно, что-то пропустил. Развивая свое понимание в этой области ...IIUC «yield *» означает, что каждое значение внутреннего «итерабельного» дается. Насколько я могу судить по этому примеру. Я бы предположил, что реальным примером может быть список слишком больших чисел, чтобы вписаться в память. – Ben

ответ

4

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

function* numbers(upto, transform) { 
 
    let n = 0; 
 
    while (n < upto) { 
 
     yield transform(n); 
 
     ++n; 
 
    } 
 
} 
 

 
const timesTwo = n => n * 2; 
 

 
const generator = numbers(31, timesTwo); 
 

 
for (const i of generator) { 
 
    console.log(i); // 0 2 4 6 8... 60 
 
}

Live on Babel's REPL для тех, чьи браузеры не будут работать выше.


Мы могли использовать оригинальное определение numbers, но мы должны либо применить преобразование жадности вместо лениво, или мы должны использовать итератор в массива (массив будет создан все сразу независимо). Вот что последний один:

function* numbers(upto, transform) { 
 
    for (const n of Object.keys([...Array(upto)])) { 
 
    yield transform(n); 
 
    } 
 
} 
 

 
const timesTwo = n => n * 2; 
 

 
const generator = numbers(31, timesTwo); 
 

 
for (const i of generator) { 
 
    console.log(i); // 0 2 4 6 8... 60 
 
}

Live on Babel's REPL.


Мы могли бы выделить два аспект numbers там и имеем общее назначение transform функцию, которая в основном версия генератора map:

function* transform(iterable, f) { 
    for (const v of iterable) { 
    yield f(v); 
    } 
} 

Тогда мы можем использовать на более основном numbers:

function* transform(iterable, f) { 
 
    for (const v of iterable) { 
 
    yield f(v); 
 
    } 
 
} 
 

 
function* numbers(upto) { 
 
    yield* Object.keys([...Array(upto)]); 
 
} 
 

 
const timesTwo = n => n * 2; 
 

 
const generator = transform(numbers(31), timesTwo); 
 

 
for (const i of generator) { 
 
    console.log(i); // 0 2 4 6 8... 60 
 
}

On Babel's REPL


Side Примечание: Я уверен, что вы знаете, но для любых люркеров, тем numbers в вопросе [и несколько из них ниже] перебирает серии строк: "0", "1" и т. Д. Но тогда, когда мы умножаемся с ними, их принуждают к номерам. На самом деле есть ряд чисел, основанных на numbers подходе вопрос, мы должны были бы

yield* Object.keys([...Array(upto)]).map(Number)); 
+0

Предположительно, если я хочу лениться преобразовать с делегацией мне нужно построить новую итерабельность, в которой преобразование выполняется лениво. – Ben

+0

@BenAston: Точно. Вот что я сделал в своем втором примере выше, затем я вернулся только сейчас и отделил его в третьем. –

0

function lazy(f) { 
 
    return function*(iter) { 
 
     for(const v of iter) { 
 
      yield f(v); 
 
     } 
 
    } 
 
} 
 

 
function* numbers(upto, transform) { 
 
    yield* lazy(transform)(Object.keys([...Array(upto)])); 
 
} 
 

 
function timesTwo(n) { 
 
    console.log('times two called on ', n); 
 
    return n*2; 
 
} 
 

 
var generator = numbers(11, timesTwo) 
 

 
for(var i of generator) { 
 
    console.log(i); // 0 2 4 6 8... 20 
 
}

Смежные вопросы