@@ -3133,6 +3133,58 @@ pub trait Itertools: Iterator {
31333133 self . k_largest_by ( k, k_smallest:: key_to_cmp ( key) )
31343134 }
31353135
3136+ /// Consumes the iterator and return an iterator of the last `n` elements.
3137+ ///
3138+ /// It allocates up to `n` elements.
3139+ /// The iterator, if directly collected to a `Vec`, is converted
3140+ /// without any extra copying or allocation cost.
3141+ ///
3142+ /// ```
3143+ /// use itertools::{assert_equal, Itertools};
3144+ ///
3145+ /// let v = vec![5, 9, 8, 4, 2, 12, 0];
3146+ /// assert_equal(v.iter().tail(3), &[2, 12, 0]);
3147+ /// assert_equal(v.iter().tail(10), &v);
3148+ ///
3149+ /// assert_equal((0..100).tail(10), 90..100);
3150+ ///
3151+ /// assert_equal((0..100).filter(|x| x % 3 == 0).tail(10), (72..100).step_by(3));
3152+ /// ```
3153+ ///
3154+ /// For double ended iterators without side-effects, you might prefer
3155+ /// `.rev().take(n).rev()` to have a similar result (lazy and non-allocating)
3156+ /// without consuming the entire iterator.
3157+ #[ cfg( feature = "use_alloc" ) ]
3158+ fn tail ( self , n : usize ) -> VecIntoIter < Self :: Item >
3159+ where
3160+ Self : Sized ,
3161+ {
3162+ match n {
3163+ 0 => {
3164+ self . last ( ) ;
3165+ Vec :: new ( )
3166+ }
3167+ 1 => self . last ( ) . into_iter ( ) . collect ( ) ,
3168+ _ => {
3169+ let mut iter = self . fuse ( ) ;
3170+ let mut data: Vec < _ > = iter. by_ref ( ) . take ( n) . collect ( ) ;
3171+ // Update `data` cyclically.
3172+ let idx = iter. fold ( 0 , |i, val| {
3173+ data[ i] = val;
3174+ if i + 1 == n {
3175+ 0
3176+ } else {
3177+ i + 1
3178+ }
3179+ } ) ;
3180+ // Respect the insertion order.
3181+ data. rotate_left ( idx) ;
3182+ data
3183+ }
3184+ }
3185+ . into_iter ( )
3186+ }
3187+
31363188 /// Collect all iterator elements into one of two
31373189 /// partitions. Unlike [`Iterator::partition`], each partition may
31383190 /// have a distinct type.
0 commit comments