Skip to content

Commit ae740f2

Browse files
committed
Added interleave_shortest adaptor.
1 parent 9177e0e commit ae740f2

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

src/adaptors.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,84 @@ impl<I, J> Iterator for Interleave<I, J> where
7070
}
7171
}
7272

73+
/// An iterator adaptor that alternates elements from the two iterators until
74+
/// one of them runs out.
75+
///
76+
/// This iterator is *fused*.
77+
///
78+
/// See [*.interleave_shortest()*](trait.Itertools.html#method.interleave_shortest)
79+
/// for more information.
80+
#[derive(Clone)]
81+
pub struct InterleaveShortest<I, J> where
82+
I: Iterator,
83+
J: Iterator<Item=I::Item>,
84+
{
85+
it0: Fuse<I>,
86+
it1: Fuse<J>,
87+
phase: bool, // false ==> it0, true ==> it1
88+
}
89+
90+
impl<I, J> InterleaveShortest<I, J> where
91+
I: Iterator,
92+
J: Iterator<Item=I::Item>,
93+
{
94+
/// Create a new **InterleaveShortest** iterator.
95+
pub fn new(a: I, b: J) -> InterleaveShortest<I, J> {
96+
InterleaveShortest {
97+
it0: a.fuse(),
98+
it1: b.fuse(),
99+
phase: false,
100+
}
101+
}
102+
}
103+
104+
impl<I, J> Iterator for InterleaveShortest<I, J> where
105+
I: Iterator,
106+
J: Iterator<Item=I::Item>,
107+
{
108+
type Item = I::Item;
109+
110+
#[inline]
111+
fn next(&mut self) -> Option<I::Item> {
112+
match self.phase {
113+
false => match self.it0.next() {
114+
None => None,
115+
e => {
116+
self.phase = true;
117+
e
118+
}
119+
},
120+
true => match self.it1.next() {
121+
None => None,
122+
e => {
123+
self.phase = false;
124+
e
125+
}
126+
},
127+
}
128+
}
129+
130+
#[inline]
131+
fn size_hint(&self) -> (usize, Option<usize>) {
132+
fn bound(a: usize, b: usize) -> Option<usize> {
133+
use std::cmp::min;
134+
2usize.checked_mul(min(a, b))
135+
.and_then(|lhs| lhs.checked_add(if a > b { 1 } else { 0 }))
136+
}
137+
138+
let (l0, u0) = self.it0.size_hint();
139+
let (l1, u1) = self.it1.size_hint();
140+
let lb = bound(l0, l1).unwrap_or(usize::max_value());
141+
let ub = match (u0, u1) {
142+
(None, None) => None,
143+
(Some(u0), None) => 2usize.checked_mul(u0),
144+
(None, Some(u1)) => 2usize.checked_mul(u1).and_then(|l| l.checked_add(1)),
145+
(Some(u0), Some(u1)) => bound(u0, u1)
146+
};
147+
(lb, ub)
148+
}
149+
}
150+
73151
/// **Deprecated:** Use *.map_fn()* instead.
74152
pub struct FnMap<B, I> where
75153
I: Iterator,

src/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use std::fmt;
3939

4040
pub use adaptors::{
4141
Interleave,
42+
InterleaveShortest,
4243
Product,
4344
PutBack,
4445
PutBackN,
@@ -240,6 +241,25 @@ pub trait Itertools : Iterator {
240241
Interleave::new(self, other.into_iter())
241242
}
242243

244+
/// Alternate elements from two iterators until one of them runs out.
245+
///
246+
/// Iterator element type is **Self::Item**.
247+
///
248+
/// This iterator is *fused*.
249+
///
250+
/// ```
251+
/// use itertools::Itertools;
252+
///
253+
/// let it = (0..5).interleave_shortest(vec![7, 8]);
254+
/// itertools::assert_equal(it, vec![0, 7, 1, 8, 2]);
255+
/// ```
256+
fn interleave_shortest<J>(self, other: J) -> InterleaveShortest<Self, J::IntoIter> where
257+
J: IntoIterator<Item=Self::Item>,
258+
Self: Sized
259+
{
260+
InterleaveShortest::new(self, other.into_iter())
261+
}
262+
243263
/// An iterator adaptor to insert a particular value
244264
/// between each element of the adapted iterator.
245265
///

tests/tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,31 @@ fn interleave() {
9696
it::assert_equal(it, rs.iter());
9797
}
9898

99+
#[test]
100+
fn interleave_shortest() {
101+
let v0: Vec<i32> = vec![0, 2, 4];
102+
let v1: Vec<i32> = vec![1, 3, 5, 7];
103+
let it = v0.into_iter().interleave_shortest(v1.into_iter());
104+
assert_eq!(it.size_hint(), (6, Some(6)));
105+
assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5]);
106+
107+
let v0: Vec<i32> = vec![0, 2, 4, 6, 8];
108+
let v1: Vec<i32> = vec![1, 3, 5];
109+
let it = v0.into_iter().interleave_shortest(v1.into_iter());
110+
assert_eq!(it.size_hint(), (7, Some(7)));
111+
assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5, 6]);
112+
113+
let i0 = ::std::iter::repeat(0);
114+
let v1: Vec<_> = vec![1, 3, 5];
115+
let it = i0.interleave_shortest(v1.into_iter());
116+
assert_eq!(it.size_hint(), (7, Some(7)));
117+
118+
let v0: Vec<_> = vec![0, 2, 4];
119+
let i1 = ::std::iter::repeat(1);
120+
let it = v0.into_iter().interleave_shortest(i1);
121+
assert_eq!(it.size_hint(), (6, Some(6)));
122+
}
123+
99124
#[test]
100125
fn times() {
101126
assert!(it::times(0).count() == 0);

0 commit comments

Comments
 (0)