vitaly-t / iter-ops

Basic operations on iterables
https://vitaly-t.github.io/iter-ops
MIT License
136 stars 5 forks source link

Add operator flat #107

Closed RebeccaStevens closed 2 years ago

RebeccaStevens commented 2 years ago

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

There is already the spread operator which is almost the same as flat; except that spreadthrows when it encounters a non-iterable while flat should keep the value as is.

For example:

const data = [1, [2, 3], 4, [[5, 6]]];

pipe(data, spread());      // => throws "Value at index 0 is not iterable: 1"
pipe(data, flat());        // => [1, 2, 3, 4, [5, 6]];

Alternatively the behavior of spread could be altered to work like flat.

vitaly-t commented 2 years ago

Alternatively the behavior of spread could be altered to work like flat.

The way spread works is consistent with how JavaScript's native spread operator works, i.e. it throws a similar error if you pass it a non-iterable.

For that reason, the only good option to consider is to add a separate flat operator.

vitaly-t commented 2 years ago

I have started working on this, within branch flat.

vitaly-t commented 2 years ago

I was just thinking, that our flat implementation would be different from Array.prototype.flat(), because the latter does not split strings into letters, for example, while we probably should?

Operator spread will spread everything iterable. Now I'm trying to decide whether our flat should do the same or to be consistent with Array.prototype.flat()?

@RebeccaStevens What do you think?

vitaly-t commented 2 years ago

@RebeccaStevens

Since I haven't quite decided, plus the recursive resolution (per optional depth) makes it way more complex an operator.

All my latest is inside flat branch, though it is not much yet. But if you want to have a go at it - you're most welcome!

RebeccaStevens commented 2 years ago

I'll take a look at it and see what I can do.

If it proves too difficult, maybe we just drop this operator and have flat just be an alias for spread.

vitaly-t commented 2 years ago

After having looked at the Array flat, it looks way different, as it supports nesting, plus doesn’t throw errors. Nesting is the tricky part, it would be the first operator that requires recursion.

vitaly-t commented 2 years ago

On my second take, I realized it is actually much simpler than I initially thought. In fact, it is even simpler than spread logic.

vitaly-t commented 2 years ago

flatSync is finished and checked in, in branch flat ;) See code. It is as trivial as I thought :)

flatAsync is yet to be written...

vitaly-t commented 2 years ago

The async version is way more tricky, as it needs to handle (differently) both sync and async nested sub-iterables.

vitaly-t commented 2 years ago

The async flat has been implemented.

What remains:

vitaly-t commented 2 years ago

This now has been merged into master.

vitaly-t commented 2 years ago

I have published 2.0.0-beta.2 that includes flat operator :wink:

vitaly-t commented 2 years ago

Operator flat is now fully finished.

@RebeccaStevens If you find any problem with it, we can open a new issue for it ;)

vitaly-t commented 2 years ago

The only thing I do not like about this new operator is its name - flat.

All other operators in the library are either nouns that denote the result, or verbs - denoting the action. And flat doesn't do any of that, it's supposed to be called flatten.

The only reason we called it flat is to have the visual match with the stupid Array.prototype.flat() naming. 😆

vitaly-t commented 2 years ago

Something I'm not sure about output types:

image

The type happens to depend on the depth parameter here, so I'm not sure what correct output template should be...

@RebeccaStevens Any idea?

RebeccaStevens commented 2 years ago

Ah, that should be achieveable with overloads. Not sure if it can be generalized, will need to look into it.