I could go with an iterator equivalent, but I'd like to defer that to
the seemingly-planned "iterlib" thing that's been considered since
before ES2015 was released. Something that works with arrays is good
enough for now.
BTW, your `ziperator` isn't really the same as my `Array.interpolate`
(which is better named `Array.interleave`). It needs to be this:
```js
function *ziperator(...iters) {
for (let i = 0; i < iters.length; i++) {
iters[i] = iters[i][Symbol.iterator]()
}
while (true) {
for (let i = 0; i < iters.length; i++) {
const {done, value} = iters[i].next()
if (done) return undefined
yield value
}
}
}
```
The optimized version is pretty straightforward (using private fields
+ methods here):
```js
function ziperator(...iters) { return new InterleavedIterator(iters) }
class InterleavedIterator {
#iters, #index
constructor(iters) { this.#iters = iters; this.#index = 0 }
[Symbol.iterator]() { return this }
next(value) { return this.#invoke("next", value) }
throw(value) { return this.#invoke("throw", value) }
return(value) { return this.#invoke("return", value) }
#invoke(method, value) {
if (this.#iters == null) return {done: true, value: undefined}
const index = this.#index
this.#index = (index + 1) % this.#iters.length
const {done, value} = this.#iters[index][method](value)
if (done) this.#iters = undefined
return {done, value}
}
}
```
-----
Isiah Meadows
[email protected]
www.isiahmeadows.com
On Fri, Dec 14, 2018 at 2:55 PM Mike Samuel <[email protected]> wrote:
>
>
>
> On Fri, Dec 14, 2018 at 2:26 PM Isiah Meadows <[email protected]> wrote:
>>
>> The main difference with that loop is that it's generalized to any number of
>> arrays, not just two with the second array having length one less than the
>> first. Otherwise, it'd look exactly the same. BTW, I like this route
>> (`Array.interleave`) better since it doesn't have to result in just a single
>> string result - it could just be an array of strings plugged into some API
>> instead, or it could be procedurally streamed out in chunks.
>
>
> Fair enough.
> If you're not looking for something template tag specific then a simple zip
> over iterators should do it?
>
> function *ziperator(iterators) {
> let progressed;
> do {
> progressed = false;
> for (let iterator of iterators) {
> for (let element of iterator) {
> yield element;
> progressed = true;
> break;
> }
> }
> } while (progressed);
> }
>
> console.log(Array.from(ziperator([ ['a', 'b', 'c'][Symbol.iterator](), [1,
> 2][Symbol.iterator]() ])).join(''));
> // -> a1b2c
>
> (but optimized :)
>
>
>
>>
>> On Fri, Dec 14, 2018 at 14:04 Mike Samuel <[email protected]> wrote:
>>>
>>>
>>>
>>> On Fri, Dec 14, 2018 at 12:51 PM Isiah Meadows <[email protected]>
>>> wrote:
>>>>
>>>> I'll point out Kai could be on to something, although I disagree `zip`
>>>> would be the right abstraction. Maybe `Array.interleave(...arrays)`? You
>>>> could do `Array.interleave(template, args).map(String).join("")` for
>>>> similar effect, and it'd be more generally useful.
>>>>
>>>> The key here is that iteration would stop after the index hits any array's
>>>> length, so it'd be polyfilled kinda like this:
>>>>
>>>> ```js
>>>> Array.interpolate = (...args) => {
>>>> let ret = []
>>>> let lengths = []
>>>> let count = 0
>>>> for (let i = 0; i < args.length; i++) {
>>>> lengths[i] = args[i].count
>>>> }
>>>> for (let index = 0; ; index++) {
>>>> for (let i = 0; i < args.length; i++) {
>>>> if (index === lengths[i]) return ret
>>>> ret[count++] = args[i][index]
>>>> }
>>>> }
>>>> }
>>>> ```
>>>>
>>>> (This could be optimized, though.)
>>>
>>>
>>> As a data point, something like this loop appears in most of the template
>>> tags I've written but
>>> it's never had these precise semantics so I didn't bother putting it into
>>> template-tag-common.
>>>
>>> That library makes it easy to split the operation of a template tag into 3
>>> stages:
>>> 1. An optional configuration stage accessed by calling the template tag as
>>> a regular function: mytag({ /* options */)`...`
>>> 2. Static analysis over the strings. This is memoized.
>>> 3. Computing a result from (options, strings, results of step 2,
>>> interoplated values)
>>>
>>> The final loop (step 3) in the template tags I maintain tends to looks like
>>>
>>> function computeResult(options, staticState /* from step 2 */, strings,
>>> ...values) {
>>> let n = values.length; // Could do Math.max(strings.length - 1,
>>> values.length);
>>> let result = strings[0]; // Usually strings.raw
>>> for (let i = 0; i < n;) {
>>> const interpolatedValue = f(options, staticState[i], values[i]);
>>> // Sometimes code here looks backwards at the result to see if it needs
>>> to avoid token-merging hazards.
>>> result += interpolatedValue;
>>> result += strings[++i];
>>> }
>>> return wrapResult(result); // Produce a value of a type that
>>> encapsulates the tag's security guarantees.
>>> }
>>>
>>>
>>>
>>>
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss