rust-itertools / itertools

Extra iterator adaptors, iterator methods, free functions, and macros.
https://docs.rs/itertools/
Apache License 2.0
2.76k stars 309 forks source link

Add a way to create a finite iterator from the initial state and a function to compute the next state. #999

Open matj1 opened 2 days ago

matj1 commented 2 days ago

I want a way to easily create a finite iterator from an initial state and a function creating the next state, but, unlike the present function iterate, it takes a function which gives the new state already wrapped in Option, which allows the function to end the iterator. The result of iterate will never end.

I use this implementation based on iterate, and I could commit it to this repository, but I would like to discuss how it should be named and if it could be done better.

pub fn iterate_f<St, F>(initial_state: Option<St>, f: F) -> Iterate<St, F>
where
    F: FnMut(&St) -> Option<St>,
{   IterateF {
        state: initial_state,
        f } }

#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IterateF<St, F> {
    state: Option<St>,
    f: F }

impl<St, F> Iterator for IterateF<St, F>
where
    F: FnMut(&St) -> Option<St>,
{   type Item = St;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let next_state = match &self.state {
            Some(x) => (self.f)(x),
            None => None };
        replace(&mut self.state, next_state) } }

impl<St, F> FusedIterator for IterateF<St, F>
where
    F: FnMut(&St) -> Option<St>,
{}
jswrenn commented 2 days ago

Does core::iter::from_fn meet your requirements?

matj1 commented 1 day ago

It does almost what I want, but I dislike that it needs an external variable to track the state. I prefer a single expression to create the iterator. If I enclose the variable with the call to from_fn in a scope to have it as a single expression, I get an error that the variable does not live long enough.