Composing generator producer of values - javascript

How can I compose a producer generator that gets values externally with another generator? If producer yields a value within the generator then it works, but when I send a value with next I get undefined. Is there a way to do this?
function* producer() {
while (true) {
yield // want to send values here
}
}
function* take(n, gen) {
var i = 0
for (var x of gen) {
if (i <= n) {
yield x // want the value sent to the producer
i += 1
} else {
break
}
}
}
var prod = producer()
var res = take(5, prod)
// How can I send values to the producer
// and make the result yield those values?
res.next() // init
console.log(res.next(1)) // {value: undefined, done: false}
console.log(res.next(2)) // {value: undefined, done: false}
// ...
// I want to get
// {value: 1, done: false}
// {value: 2, done: false}
// ...

To get a value which is sent to next(), you should use the result that is returned by yield. I am not quite sure what your end goal is, but here is your modified example:
let producer = function*() {
var nextResult = undefined;
while(true) {
nextResult = yield nextResult;
console.log("produce " + nextResult);
}
}
let take = function*(number, items) {
var count = 0;
var item = undefined;
while (count <= number) {
items.next(item);
item = yield item;
console.log("take " + item);
count += 1;
}
}
var res = take(2, producer())
res.next() // init
console.log('result ' + res.next(3).value)
console.log('result ' + res.next(2).value)
This outputs:
take 3
produce 3
result 3
take 2
produce 2
result 2
ES6 fiddle link

Related

A variable doesn't get update inside my Factory Function on JavaScript

So I am basically trying to change the variable "status" when I execute the code below.
const Ship = (length) => {
let status = "good"
let array = []
for (let i = 1; i <= length; i++) {
array.push(i)
}
const hit = (number) => {
if (!number) {
return array
}
array[number - 1] = number + 10
status = "bad"
}
return {
length,
hit,
array,
status
}
}
const ships = Ship(2)
console.log(ships.status) //initial status
console.log(ships.array) //initial array
ships.hit(1)
console.log(ships.array) //modified array
console.log(ships.status) //not modified status
It should work,since the array gets modified, but for some reason it doesn't.
I want to know WHY it doesn't work, not a work around.
You declare the hit function but didn't run it,
const hit = (number) => {
if (!number) {
return array
}
array[number - 1] = number + 10
status = "bad"
}
hit(number) <---
You're getting a copy of the status variable in function scope via closure. I would suggest using class semantics for your usecase
class Ship {
constructor(length) {
this.array = []
this.status = "good"
for (let i = 1; i <= length; i++) {
this.array.push(i)
}
}
hit = (number) => {
if (!number) {
return this.array
}
this.array[number - 1] = number + 10
this.status = "bad"
}
}

iteration associated object js

i want to use Symbol.iterator in object for iteration associated object
i need to return all key and all value in loop
this is my output :
let price = {
money:2000,
edit_photo:{
yes:100,
no:0
},
photo_type:{
personal:300,
sport:400,
fashion:500,
commercial:600
},
[Symbol.iterator](){
let items = Object.keys(this);
let step = 0;
return{
next(){
let object = {
done: step >= items.length,
value: items[step]
}
step++;
return object;
}
}
}
}
for (let item of price) {
console.log(item)
}
i have a problem to scroll all value
You formed your Symbol.iterator incorrectly. The Symbol.iterator is technically a generator and not an iterator. A generator function needs to be marked with a *.
const someObj = {
*[Symbol.iterator]() {
yield 'a';
yield 'b';
}
}
That way your object knows to actually use it as a generator function.
Now that we're using the right type of function, we have to return the right type of value. Well, yield the right type of value.
Since you are looking to return the key and value for each object item, the object we're yielding might looks like this:
yield {
done: false,
key: items[step],
value: this[items[step]]
}
To make sure we yield each item of the object, we put this inside of a while loop.
while (steps < items.length) {
yield { /* ... */ };
step++;
}
Once the while loop exits, we yield our final object.
yield {
done: true,
value: this,
};
The complete code based on your example is below. Citing my source: MDN here.
let price = {
money:2000,
edit_photo:{
yes:100,
no:0
},
photo_type:{
personal:300,
sport:400,
fashion:500,
commercial:600
},
*[Symbol.iterator](){
let items = Object.keys(this);
let step = 0;
while (step < items.length) {
yield {
done: false,
key: items[step],
value: this[items[step]]
};
step++;
}
yield {
done: true,
value: this,
}
}
}
for (let item of price) {
console.log(item);
}

filter values from a javascript generator-stream

I've recently watched this interesting video on the computerphile and decided to implement the sieve-algorithm using JavaScript generators. I'm pretty confident with JavaScript in general but have never worked with generators directly before.
Here's what I have so far:
function* nextNaturalNumber(n) {
yield n;
yield* nextNaturalNumber(n + 1);
}
function* sieve(n) {
let count = 0;
let g = nextNaturalNumber(2);
while (count++ < n) {
const possiblePrime = g.next().value;
yield possiblePrime;
// here's where I'm stuck:
// how can I filter the values from the nextNaturalNumber-generator stream that are not divisible by 2?
}
}
// print the first 10 primes
for (const prime of sieve(10)) {
console.log(prime);
}
As mentioned in the code-comment, I'm stuck on how to filter the values from the generator stream that are not divisible by 2 and thus performing the "sieve"-operation. Is there a simple way to do this (as in Python with yield from sieve(i for i in s if i%n !=0)) in JavaScript?
Unfortunately, Javascript does not have that many good iterator operations. You can, however, just make a filter function that loops through the iterator and yield values that match:
function* nextNaturalNumber(n) {
// switch to iterative to avoid stack overflows
while(true) {
yield n;
n ++;
}
}
function* filterIter(iter, pred) {
for (const item of iter) {
if (pred(item)) {
yield item;
}
}
}
function* sieve(n) {
let count = 0;
let g = nextNaturalNumber(2);
while (count++ < n) {
const possiblePrime = g.next().value;
yield possiblePrime;
g = filterIter(g, v => v % possiblePrime != 0);
}
}
// print the first 10 primes
for (const prime of sieve(10)) {
console.log(prime);
}
With the following you get only odd values from your stream:
do {
val = g.next().value;
} while (!(val%2));
Here you can test it in your code:
function* nextNaturalNumber(n) {
yield n;
yield* nextNaturalNumber(n + 1);
}
function* sieve(n) {
let count = 0;
let g = nextNaturalNumber(2);
while (count++ < n) {
let val;
do {
val = g.next().value;
} while (!(val%2));
const possiblePrime=val;
yield possiblePrime;
}
}
// print the first 10 primes
for (const prime of sieve(10)) {
console.log(prime);
}
I worry that, maybe, you're trying to be more Pythonic than is really ideal for JS coding. JS encourages being explicit about your ongoing variables (rather than hiding them in the calling and filtering stack like Python does). How about this?
//
// You want to look through all the natural numbers...
//
function* nextNaturalNumber(n) {
while(true) {
yield n;
n++;
}
}
function* sieve() {
//
// Keep track of the primes you've seen previously
//
let previousPrimes = [];
for (const possiblePrime of nextNaturalNumber(2)) {
//
// And for each number, check whether it's divisible by any of those primes
//
if (!previousPrimes.find((test) => (possiblePrime % test === 0))) {
//
// If it's not, return it as a prime and add it to the
// primes you've (now) already seen
//
yield possiblePrime;
previousPrimes.push(possiblePrime);
}
}
}
let generator = sieve();
for(let i = 0; i < 10; i++) {
console.log(generator.next().value);
}

How to peek at the next value in a Javascript Iterator

Let's say I have an iterator:
function* someIterator () {
yield 1;
yield 2;
yield 3;
}
let iter = someIterator();
... that I look at the next element to be iterated:
let next = iter.next(); // {value: 1, done: false}
... and I then use the iterator in a loop:
for(let i of iterator)
console.log(i);
// 2
// 3
The loop will not include the element looked at. I wish to see the next element while not taking it out of the iteration series.
In other words, I wish to implement:
let next = peek(iter); // {value: 1, done: false}, or alternatively just 1
for(let i of iterator)
console.log(i);
// 1
// 2
// 3
... and I wan't to do it without modifying the code for the iterable function.
What I've tried is in my answer. It works (which is why I made it an answer), but I worry that it builds an object that is more complex than it has to be. And I worry that it will not work for cases where the 'done' object is something different than { value = undefined, done = true }. So any improved answers are very much welcome.
Instead of a peek function, I built a peeker function that calls next, removing the element from the iterator, but then adds it back in by creating an iterable function that first yields the captured element, then yields the remaining items in the iterable.
function peeker(iterator) {
let peeked = iterator.next();
let rebuiltIterator = function*() {
if(peeked.done)
return;
yield peeked.value;
yield* iterator;
}
return { peeked, rebuiltIterator };
}
function* someIterator () { yield 1; yield 2; yield 3; }
let iter = someIterator();
let peeked = peeker(iter);
console.log(peeked.peeked);
for(let i of peeked.rebuiltIterator())
console.log(i);
Just a bit different idea is to use wrapper that makes an iterator kind of eagier.
function peekable(iterator) {
let state = iterator.next();
const _i = (function* (initial) {
while (!state.done) {
const current = state.value;
state = iterator.next();
const arg = yield current;
}
return state.value;
})()
_i.peek = () => state;
return _i;
}
function* someIterator () { yield 1; yield 2; yield 3; }
let iter = peekable(someIterator());
let v = iter.peek();
let peeked = iter.peek();
console.log(peeked.value);
for (let i of iter) {
console.log(i);
}

Distribute iterator items over subiterators

I am playing with iterators in javascript. I found a way of chaining them so I don't have to nest them, just for readability.
It kind of works exactly like an array map chain.
What I like to do is distribute the items of the generator over a few sub iterators, catch the results and feed them to the next iterator. Such that the outcome will be this:
4
6
8
7
9
11
Given this piece of code:
"use strict";
const _ = require('lodash');
let things = chain([
gen,
addOne,
distribute([
addOne,
addTwo,
addThree
]),
addOne
]);
for(let thing of things) {
console.log(thing);
}
//////////////// DEFENITIONS ////////////////////
function* gen() {
yield* [1, 2, 3, 4, 5, 6];
}
function* addOne(iterator) {
for(let item of iterator) {
yield (item + 1)
}
}
function* addTwo(iterator) {
for(let item of iterator) {
yield (item + 2)
}
}
function* addThree(iterator) {
for(let item of iterator) {
yield (item + 3)
}
}
const distribute = _.curry(function* (iterators, iterator) {
// magic
});
function chain(iterators) {
return iterators.reduce((prevIterator, thisIterator, index) => {
if(index === 0) {
return thisIterator();
}
return thisIterator(prevIterator);
}, null);
}
Eventually i would like to add a distribution function to the distribution iterator, so it can determine which item to pass to which subiterator. For now it is just based on the order.
Question: How do I write a distribution iterator that takes a few subiterators as an argument and passes the results through to the next iterator.
It seems overly complex, but it works
const distribute = _.curry(function* (iterators, mainIterator) {
let iteratorIndex = 0;
let done = [];
for(let iterator of iterators) {
iterators[iteratorIndex] = iterator(mainIterator);
done.push(false);
iteratorIndex++;
}
while(true) {
let iteratorIndex = 0;
for(let iterator of iterators) {
let next = iterator.next();
done[iteratorIndex] = next.done;
if(!next.done) {
yield next.value;
}
iteratorIndex++;
}
if(done.every(done => done)) {
return;
}
}
});
And finally with a distribution function:
const distribute = _.curry(function* (genIteratorIndex, iterators, mainIterator) {
let iteratorIndex = 0;
let done = [];
// instantiate iterators
for(let iterator of iterators) {
iterators[iteratorIndex] = iterator(mainIterator);
done.push(false);
iteratorIndex++;
}
// Pass stuff through
while(true) {
let next = iterators[genIteratorIndex.next().value].next();
done[iteratorIndex] = next.done;
if(!next.done) {
yield next.value;
}
if(done.every(done => done === true)) {
return;
}
}
});
function* subSequent(len) {
let curr = 0;
while(true) {
if(curr === len) {
curr = 0;
}
yield curr;
curr++;
}
}
let things = chain([
gen,
addOne,
distribute(subSequent(3), [
addOne,
addTwo,
addThree
]),
addOne
]);

Categories

Resources