Skip to content

Commit 0d4930e

Browse files
New Itertools::tail
The `.tail(1)` test is for code coverage.
1 parent 6a69bd9 commit 0d4930e

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

src/lib.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3144,6 +3144,57 @@ pub trait Itertools: Iterator {
31443144
self.k_largest_by(k, k_smallest::key_to_cmp(key))
31453145
}
31463146

3147+
/// Consumes the iterator and return an iterator of the last `n` elements.
3148+
///
3149+
/// The iterator, if directly collected to a `Vec`, is converted
3150+
/// without any extra copying or allocation cost.
3151+
///
3152+
/// ```
3153+
/// use itertools::{assert_equal, Itertools};
3154+
///
3155+
/// let v = vec![5, 9, 8, 4, 2, 12, 0];
3156+
/// assert_equal(v.iter().tail(3), &[2, 12, 0]);
3157+
/// assert_equal(v.iter().tail(10), &v);
3158+
///
3159+
/// assert_equal(v.iter().tail(1), v.iter().last());
3160+
///
3161+
/// assert_equal((0..100).tail(10), 90..100);
3162+
/// ```
3163+
///
3164+
/// For double ended iterators without side-effects, you might prefer
3165+
/// `.rev().take(n).rev()` to have a similar result (lazy and non-allocating)
3166+
/// without consuming the entire iterator.
3167+
#[cfg(feature = "use_alloc")]
3168+
fn tail(self, n: usize) -> VecIntoIter<Self::Item>
3169+
where
3170+
Self: Sized,
3171+
{
3172+
match n {
3173+
0 => {
3174+
self.last();
3175+
Vec::new()
3176+
}
3177+
1 => self.last().into_iter().collect(),
3178+
_ => {
3179+
let mut iter = self.fuse();
3180+
let mut data: Vec<_> = iter.by_ref().take(n).collect();
3181+
// Update `data` cyclically.
3182+
let idx = iter.fold(0, |i, val| {
3183+
data[i] = val;
3184+
if i + 1 == n {
3185+
0
3186+
} else {
3187+
i + 1
3188+
}
3189+
});
3190+
// Respect the insertion order.
3191+
data.rotate_left(idx);
3192+
data
3193+
}
3194+
}
3195+
.into_iter()
3196+
}
3197+
31473198
/// Collect all iterator elements into one of two
31483199
/// partitions. Unlike [`Iterator::partition`], each partition may
31493200
/// have a distinct type.

tests/quick.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,4 +1949,9 @@ quickcheck! {
19491949
result_set.is_empty()
19501950
}
19511951
}
1952+
1953+
fn tail(v: Vec<i32>, n: u8) -> bool {
1954+
let n = n as usize;
1955+
itertools::equal(v.iter().tail(n), &v[v.len().saturating_sub(n)..])
1956+
}
19521957
}

0 commit comments

Comments
 (0)