Skip to content

Commit 46a739f

Browse files
committed
Add Itertool::k_smallest method, in std context
1 parent 4114081 commit 46a739f

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/k_smallest.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::collections::BinaryHeap;
2+
use std::cmp::Ord;
3+
4+
pub(crate) fn k_smallest<T: Ord, I: Iterator<Item = T>>(mut iter: I, k: usize) -> BinaryHeap<T> {
5+
if k == 0 { return BinaryHeap::new(); }
6+
7+
let mut heap = iter.by_ref().take(k).collect::<BinaryHeap<_>>();
8+
9+
for i in iter {
10+
// Guaranteed not-None, since we keep exactly k>0 elements in the heap.
11+
let mut lorgest = heap.peek_mut().unwrap();
12+
if *lorgest > i { *lorgest = i; }
13+
}
14+
15+
heap
16+
}

src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ mod group_map;
194194
mod groupbylazy;
195195
mod intersperse;
196196
#[cfg(feature = "use_alloc")]
197+
mod k_smallest;
198+
#[cfg(feature = "use_alloc")]
197199
mod kmerge_impl;
198200
#[cfg(feature = "use_alloc")]
199201
mod lazy_buffer;
@@ -2284,6 +2286,39 @@ pub trait Itertools : Iterator {
22842286
v.into_iter()
22852287
}
22862288

2289+
/// Sort the k smallest elements into a new iterator, in ascending order.
2290+
///
2291+
/// **Note:** This consumes the entire iterator, and returns the result
2292+
/// as a new iterator that owns its elements.
2293+
///
2294+
/// This is guaranteed to use `k * sizeof(Self::Item) + O(1)` memory
2295+
/// and `O(n log k)` time, with `n` the number of elements in the input.
2296+
///
2297+
/// The sorted iterator, if directly collected to a `Vec`, is converted
2298+
/// without any extra copying or allocation cost.
2299+
///
2300+
/// ```
2301+
/// use itertools::Itertools;
2302+
///
2303+
/// // A random permutation of 0..15
2304+
/// let numbers = vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5];
2305+
///
2306+
/// let five_smallest = numbers
2307+
/// .into_iter()
2308+
/// .k_smallest(5);
2309+
///
2310+
/// itertools::assert_equal(five_smallest, 0..5);
2311+
/// ```
2312+
#[cfg(feature = "use_alloc")]
2313+
fn k_smallest(self, k: usize) -> VecIntoIter<Self::Item>
2314+
where Self: Sized,
2315+
Self::Item: Ord
2316+
{
2317+
crate::k_smallest::k_smallest(self, k)
2318+
.into_sorted_vec()
2319+
.into_iter()
2320+
}
2321+
22872322
/// Collect all iterator elements into one of two
22882323
/// partitions. Unlike `Iterator::partition`, each partition may
22892324
/// have a distinct type.

0 commit comments

Comments
 (0)