Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature suggestion: takeWhile() #275

Open
wellcaffeinated opened this issue Apr 29, 2022 · 5 comments
Open

feature suggestion: takeWhile() #275

wellcaffeinated opened this issue Apr 29, 2022 · 5 comments

Comments

@wellcaffeinated
Copy link
Contributor

hey there. Great library!

A takeWhile() operator would be great.

Something like this?

const takeWhile = (predicate, inclusive = false) => async function* (iterable){
  for await (const res of iterable) {
    if (!await predicate(res)){
      if (inclusive){ yield res }
      return
    }
    yield res
  }
}
const count = [1, 2, 3, 4, 5, 6, 7]
await collect(takeWhile(x => x < 5)(count))
// => [1, 2, 3, 4]
@reconbot
Copy link
Owner

reconbot commented Apr 29, 2022

Would this be the same as filter?

And thank you 😊

@wellcaffeinated
Copy link
Contributor Author

I don't think it's the same as filter because this would terminate the stream early, allowing for early collection, or ability to exit out of a find algorithm.

For example:

This could exit early once charmander is found.

const pm = await pipeline(
  getPokemon(),
  takeWhile(pokemon => pokemon.name !== 'charmander', true),
  take(-1), // this would also be great to implement btw
  collect
)
// => pm[0].name === 'charmander'

This would have to cycle through all 720 pokemon before exiting

const pm = await pipeline(
  getPokemon(),
  filter(pokemon => pokemon.name === 'charmander'),
  collect
)

Generally i think implementing some of the methods that rust's Iterator has would be great: https://doc.rust-lang.org/core/iter/trait.Iterator.html

Or perhaps looking through the list of operators that rxjs provides: https://rxjs.dev/api?type=function

@reconbot
Copy link
Owner

Well stated, thank you. Yeah this makes a lot of sense. I'd happily take a pr if you're interested.

I'll dig into the rust docs, but I'm also happy to take anything useful.

@reconbot
Copy link
Owner

What would take(-1) do? Pulling from the end of an iterable is tough when it's async, requires buffering some or all of the data depending on the operation. I've purposely not put anything in that would accidentally cause a huge performance issue.

@wellcaffeinated
Copy link
Contributor Author

Absolutely, i don't think you'd want to buffer much. I'm imagining that it would effectively release the data it doesn't need. Maybe a take(-n) could look like:

const takeRight = (count) => async function* (iterable){
  const buffer = []
  for await (const res of iterable) {
     buffer.push(res)
     if (buffer.length > count){ buffer.shift() }
  }
  while (buffer.length){ yield buffer.pop() }
}

const take = (n) => {
   if (n < 0) { return takeRight(-n) }
   else { return take(n) }
}

I'd be happy to submit some pull requests

wellcaffeinated added a commit to wellcaffeinated/streaming-iterables that referenced this issue May 4, 2022
wellcaffeinated added a commit to wellcaffeinated/streaming-iterables that referenced this issue May 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants