admin管理员组文章数量:1236529
I've got this recursive generator
var obj = [1,2,3,[4,5,[6,7,8],9],10]
function *flat(x) {
if (Array.isArray(x))
for (let y of x)
yield *flat(y)
else
yield 'foo' + x;
}
console.log([...flat(obj)])
I've got this recursive generator
var obj = [1,2,3,[4,5,[6,7,8],9],10]
function *flat(x) {
if (Array.isArray(x))
for (let y of x)
yield *flat(y)
else
yield 'foo' + x;
}
console.log([...flat(obj)])
It works fine, but I don't like the for
part. Is there a way to write it functionally? I tried
if (Array.isArray(x))
yield *x.map(flat)
which didn't work.
Is there a way to write the above function without for
loops?
5 Answers
Reset to default 3You could use rest parameters ...
and check the length of the rest array for another calling of the generator
function* flat(a, ...r) {
if (Array.isArray(a)) {
yield* flat(...a);
} else {
yield 'foo' + a;
}
if (r.length) {
yield* flat(...r);
}
}
var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10];
console.log([...flat(obj)])
.as-console-wrapper { max-height: 100% !important; top: 0; }
A similar approach but with a spread
generator for calling the handed over generator with the spreaded values.
function* spread(g, a, ...r) {
yield* g(a);
if (r.length) {
yield* spread(g, ...r);
}
}
function* flat(a) {
if (Array.isArray(a)) {
yield* spread(flat, ...a);
} else {
yield 'foo' + a;
}
}
var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10];
console.log([...flat(obj)])
.as-console-wrapper { max-height: 100% !important; top: 0; }
The map
is a good idea, but you need to reduce the resulting array of generator objects to just one generator object:
function *flat(x) {
if (Array.isArray(x))
yield *x.map(flat).reduce((a, b) => function*() { yield *a; yield *b }());
else
yield 'foo' + x;
}
var obj = [1,2,3,[4,5,[6,7,8],9],10];
console.log([...flat(obj)]);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Is there a way to write it functionally, without
for
loops?
No, not really. (Of course you can always opt for recursion instead, but I'll question the usefulness of that approach).
What we're looking for are functional combinators for iterators:
function* of(x) { // also known as `pure` or `return`
yield x;
}
function map(f) { return function* (xs) { // also known as `fmap`
for (const x of xs)
yield f(x);
}
function* join(xss) { // also known as `concat` (not `append`!) or `flatten` (but non-recursive!)
for (const xs of xss)
for (const x of xs)
yield x;
}
function chain(f) { return function* (xs) { // also known as `concatMap` or `bind`
for (const x of xs)
const ys = f(x);
for (const y of ys)
yield y;
}
// or const chain = f => compose(concat, map(f)) :-)
Now we can just treat iterators as a monad, and be no more concerned about the implementation.
As you can see, I have not used the syntax yield* xs
above which is (basically) just sugar for
for (const x of xs)
yield x;
What is looking weird in your implementation is the disparity between the outer loop and the inner non-loop. In an optimal world, there would be a yield**
syntax that did what join
does, but there's not. So we can only implement your function nicely with the above helper functions:
function* flat(x) {
if (Array.isArray(x))
yield* chain(flat)(x);
else
yield* of('foo' + x); // foreshadowing
}
or just
function flat(x) {
return Array.isArray(x) ? chain(flat)(x) : of('foo' + x);
}
You could reduce array to generator. But this looks worse than for loop to me (though is functional :) )
var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10]
function* flat(x) {
if (Array.isArray(x))
yield * x.reduceRight(
(f, y) => function*() {
yield * flat(y);
yield * f()
},
function*() {}
)()
else
yield 'foo' + x;
}
console.log([...flat(obj)])
may be something like
var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10];
function* flat(x) {
if (Array.isArray(x)) {
yield x.map(v => {
return [...flat(v)].join();
});
} else yield "foo" + x;
}
console.log([...flat(obj)]);
本文标签: javascriptyield from a list of generators created from an arrayStack Overflow
版权声明:本文标题:javascript - yield from a list of generators created from an array - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1739508793a2166394.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论