> 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.
i'm against iterator-based design-patterns and libraries, as they lack a clear fit in most javascript solutions. the vast majority of looping in UX-workflows (javascript’s primary problem-domain) are over [serializable] JSON lists/dicts/strings, where Array/Object/String looping-methods will suffice. all other use-cases are uncommon/complicated enough that custom for/while loops are usually better suited than custom-iterators. -kai > On 18 Dec 2018, at 16:42, Mike Samuel <[email protected]> wrote: > > Fair enough. > > On Tue, Dec 18, 2018, 5:29 PM Isiah Meadows <[email protected] > <mailto:[email protected]> wrote: > 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] <mailto:[email protected]> > www.isiahmeadows.com <http://www.isiahmeadows.com/> > On Fri, Dec 14, 2018 at 2:55 PM Mike Samuel <[email protected] > <mailto:[email protected]>> wrote: > > > > > > > > On Fri, Dec 14, 2018 at 2:26 PM Isiah Meadows <[email protected] > > <mailto:[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] > >> <mailto:[email protected]>> wrote: > >>> > >>> > >>> > >>> On Fri, Dec 14, 2018 at 12:51 PM Isiah Meadows <[email protected] > >>> <mailto:[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

