Skip to content

Commit 0aa9c46

Browse files
committed
Add itertools::generate
It's an easier to use alternative to unfoled, modeled after Kotlin's generateSequence.
1 parent bfe6167 commit 0aa9c46

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed

src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub mod structs {
9191
#[cfg(feature = "use_std")]
9292
pub use rciter_impl::RcIter;
9393
pub use repeatn::RepeatN;
94-
pub use sources::{RepeatCall, Unfold, Iterate};
94+
pub use sources::{RepeatCall, Generate, Unfold, Iterate};
9595
#[cfg(feature = "use_std")]
9696
pub use tee::Tee;
9797
pub use tuple_impl::{TupleBuffer, TupleWindows, Tuples};
@@ -114,7 +114,7 @@ pub use minmax::MinMaxResult;
114114
pub use peeking_take_while::PeekingNext;
115115
pub use process_results_impl::process_results;
116116
pub use repeatn::repeat_n;
117-
pub use sources::{repeat_call, unfold, iterate};
117+
pub use sources::{repeat_call, generate, unfold, iterate};
118118
pub use with_position::Position;
119119
pub use ziptuple::multizip;
120120
mod adaptors;
@@ -1888,13 +1888,13 @@ pub trait Itertools : Iterator {
18881888

18891889
/// Return a `HashMap` of keys mapped to `Vec`s of values. Keys and values
18901890
/// are taken from `(Key, Value)` tuple pairs yielded by the input iterator.
1891-
///
1891+
///
18921892
/// ```
18931893
/// use itertools::Itertools;
1894-
///
1894+
///
18951895
/// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)];
18961896
/// let lookup = data.into_iter().into_group_map();
1897-
///
1897+
///
18981898
/// assert_eq!(lookup[&0], vec![10, 20]);
18991899
/// assert_eq!(lookup.get(&1), None);
19001900
/// assert_eq!(lookup[&2], vec![12, 42]);

src/sources.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,71 @@ impl<A, St, F> Iterator for Unfold<St, F>
135135
}
136136
}
137137

138+
/// Returns an iterator that starts with the `seed` and repeatedly
139+
/// calls the `step` function to produce the next value. Iterator
140+
/// stops as soon as `None` is encountered
141+
///
142+
/// ```
143+
/// // an iterator that yields Collatz sequence.
144+
/// // https://en.wikipedia.org/wiki/Collatz_conjecture
145+
///
146+
/// use itertools::generate;
147+
///
148+
/// let collatz = generate(Some(12), |&n| {
149+
/// if n == 1 {
150+
/// None
151+
/// } else if n % 2 == 0 {
152+
/// Some(n / 2)
153+
/// } else {
154+
/// Some(3 * n + 1)
155+
/// }
156+
/// });
157+
///
158+
/// itertools::assert_equal(collatz,
159+
/// vec![12, 6, 3, 10, 5, 16, 8, 4, 2, 1]);
160+
/// ```
161+
pub fn generate<T, F>(seed: Option<T>, step: F) -> Generate<T, F>
162+
where F: FnMut(&T) -> Option<T>
163+
{
164+
Generate {
165+
next: seed,
166+
step: step,
167+
}
168+
}
169+
170+
impl<T, F> fmt::Debug for Generate<T, F>
171+
where T: fmt::Debug,
172+
{
173+
debug_fmt_fields!(Genrate, next);
174+
}
175+
176+
/// See [`unfold`](../fn.generate.html) for more information.
177+
#[derive(Clone)]
178+
#[must_use = "iterators are lazy and do nothing unless consumed"]
179+
pub struct Generate<T, F> {
180+
next: Option<T>,
181+
step: F,
182+
}
183+
184+
impl<T, F> Iterator for Generate<T, F>
185+
where F: FnMut(&T) -> Option<T>
186+
{
187+
type Item = T;
188+
189+
#[inline]
190+
fn next(&mut self) -> Option<T> {
191+
self.next.take().map(|next| {
192+
self.next = (self.step)(&next);
193+
next
194+
})
195+
}
196+
197+
#[inline]
198+
fn size_hint(&self) -> (usize, Option<usize>) {
199+
(self.next.is_some() as usize, None)
200+
}
201+
}
202+
138203
/// An iterator that infinitely applies function to value and yields results.
139204
///
140205
/// This `struct` is created by the [`iterate()`] function. See its documentation for more.

0 commit comments

Comments
 (0)