2016-12-28 2 views
3

Gegeben die folgenden. Ich möchte transform auf jedes Mitglied der iterablen zurückgegeben Object.keys träge anwenden.Zusammensetzen von Generatoren

Wie kann ich das tun?

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

Das 'transform' Parameter macht es scheinen, wie Sie glücklich sind zu haben, die Transformation in Zahlen übergegangen, anstatt sie extern zu komponieren, ist das richtig? –

+0

Ja. Offen für bessere Möglichkeiten, obwohl – Ben

+1

versuchte, ein einfaches Beispiel zu erstellen, aber möglicherweise etwas verpasst haben. Entwickeln Sie mein Verständnis in diesem Bereich ...IIUC Der 'yield *' bedeutet, dass jeder Wert des inneren 'iterable' zurückgegeben wird. Das passt, soweit ich das beurteilen kann, zu einem vereinfachenden Beispiel. Ich könnte mir vorstellen, dass ein echtes Beispiel eine Liste von Zahlen ist, die zu groß sind, um in den Speicher zu passen. – Ben

Antwort

4

Da Sie sind glücklich in numbers bestanden haben Transformations, können Sie es anwenden, wie Sie erzeugen, wenn Sie die Vorteile von numbers nehmen einen Generator zu sein:

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 für diejenigen, deren Browser das oben genannte nicht ausführen.


Wir könnte Ihre ursprüngliche Definition von numbers verwenden, aber wir würden entweder auf die mit Spannung statt faul Transformation anwenden, oder wir müssten die Iterators Array verwenden (das Array werden alle erstellt werden sofort unabhängig). Hier ist, dass letztere ein:

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.


wir dort die beiden Aspekte der numbers trennen könnte und haben eine Allzweck- transform Funktion, die im Grunde die Generator-Version map ist:

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

Dann können wir das auf einer grundlegen verwenden 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


Randbemerkung: Ich bin sicher, Sie das wissen, aber für alle Lurker, die numbers in der Frage [und ein paar von ihnen unten] iteriert über eine Reihe von Saiten: "0", "1" usw. Aber dann, wenn wir mit ihnen multiplizieren, werden sie zu Zahlen gezwungen. Um tatsächlich eine Reihe von Zahlen haben auf der Grundlage der numbers Ansatz der Frage, würden wir brauchen

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

Vermutlich wenn ich einen faulenzen möchte transformiere mit der Delegierung, die ich brauche, um ein neues iterables zu konstruieren, in dem die Transformation träge ausgeführt wird. – Ben

+0

@BenAston: Genau. Das habe ich in meinem zweiten Beispiel getan, dann bin ich gerade zurückgegangen und habe es im dritten ausgesondert. –

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 
 
}