Skip to content

Commit 8fe0b56

Browse files
committed
Add Itertools::intersperse_with
1 parent 7554521 commit 8fe0b56

File tree

2 files changed

+100
-2
lines changed

2 files changed

+100
-2
lines changed

src/intersperse.rs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl<I> Iterator for Intersperse<I>
6262
Self: Sized, F: FnMut(B, Self::Item) -> B,
6363
{
6464
let mut accum = init;
65-
65+
6666
if let Some(x) = self.peek.take() {
6767
accum = f(accum, x);
6868
}
@@ -77,3 +77,81 @@ impl<I> Iterator for Intersperse<I>
7777
})
7878
}
7979
}
80+
81+
/// An iterator adaptor to insert a particular value created by a function
82+
/// between each element of the adapted iterator.
83+
///
84+
/// Iterator element type is `I::Item`
85+
///
86+
/// This iterator is *fused*.
87+
///
88+
/// See [`.intersperse_with()`](../trait.Itertools.html#method.intersperse_with) for more information.
89+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
90+
#[derive(Debug)]
91+
pub struct IntersperseWith<I, ElemF>
92+
where I: Iterator,
93+
ElemF: FnMut() -> I::Item,
94+
{
95+
element: ElemF,
96+
iter: Fuse<I>,
97+
peek: Option<I::Item>,
98+
}
99+
100+
/// Create a new IntersperseWith iterator
101+
pub fn intersperse_with<I, ElemF>(iter: I, elt: ElemF) -> IntersperseWith<I, ElemF>
102+
where I: Iterator,
103+
ElemF: FnMut() -> I::Item
104+
{
105+
let mut iter = iter.fuse();
106+
IntersperseWith {
107+
peek: iter.next(),
108+
iter: iter,
109+
element: elt,
110+
}
111+
}
112+
113+
impl<I, ElemF> Iterator for IntersperseWith<I, ElemF>
114+
where I: Iterator,
115+
ElemF: FnMut() -> I::Item
116+
{
117+
type Item = I::Item;
118+
#[inline]
119+
fn next(&mut self) -> Option<I::Item> {
120+
if self.peek.is_some() {
121+
self.peek.take()
122+
} else {
123+
self.peek = self.iter.next();
124+
if self.peek.is_some() {
125+
Some((self.element)())
126+
} else {
127+
None
128+
}
129+
}
130+
}
131+
132+
fn size_hint(&self) -> (usize, Option<usize>) {
133+
// 2 * SH + { 1 or 0 }
134+
let has_peek = self.peek.is_some() as usize;
135+
let sh = self.iter.size_hint();
136+
size_hint::add_scalar(size_hint::add(sh, sh), has_peek)
137+
}
138+
139+
fn fold<B, F>(mut self, init: B, mut f: F) -> B where
140+
Self: Sized, F: FnMut(B, Self::Item) -> B,
141+
{
142+
let mut accum = init;
143+
144+
if let Some(x) = self.peek.take() {
145+
accum = f(accum, x);
146+
}
147+
148+
let element = &mut self.element;
149+
150+
self.iter.fold(accum,
151+
|accum, x| {
152+
let accum = f(accum, (element)());
153+
let accum = f(accum, x);
154+
accum
155+
})
156+
}
157+
}

src/lib.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ pub mod structs {
109109
pub use format::{Format, FormatWith};
110110
#[cfg(feature = "use_std")]
111111
pub use groupbylazy::{IntoChunks, Chunk, Chunks, GroupBy, Group, Groups};
112-
pub use intersperse::Intersperse;
112+
pub use intersperse::{Intersperse, IntersperseWith};
113113
#[cfg(feature = "use_std")]
114114
pub use kmerge_impl::{KMerge, KMergeBy};
115115
pub use merge_join::MergeJoinBy;
@@ -400,6 +400,26 @@ pub trait Itertools : Iterator {
400400
intersperse::intersperse(self, element)
401401
}
402402

403+
/// An iterator adaptor to insert a particular value created by a function
404+
/// between each element of the adapted iterator.
405+
///
406+
/// Iterator element type is `Self::Item`.
407+
///
408+
/// This iterator is *fused*.
409+
///
410+
/// ```
411+
/// use itertools::Itertools;
412+
///
413+
/// let mut i = 10;
414+
/// itertools::assert_equal((0..3).intersperse_with(|| { i -= 1; i }), vec![0, 9, 1, 8, 2]);
415+
/// ```
416+
fn intersperse_with<F>(self, element: F) -> IntersperseWith<Self, F>
417+
where Self: Sized,
418+
F: FnMut() -> Self::Item
419+
{
420+
intersperse::intersperse_with(self, element)
421+
}
422+
403423
/// Create an iterator which iterates over both this and the specified
404424
/// iterator simultaneously, yielding pairs of two optional elements.
405425
///

0 commit comments

Comments
 (0)