use std::collections::BinaryHeap;
pub struct WindowSort<I>
where
I: Iterator,
<I as Iterator>::Item: Ord,
{
orig: I,
window_size: usize,
heap: BinaryHeap<I::Item>,
}
impl<I> Iterator for WindowSort<I>
where
I: Iterator,
<I as Iterator>::Item: Ord,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
while self.heap.len() < self.window_size {
if let Some(item) = self.orig.next() {
self.heap.push(item);
} else {
break;
}
}
self.heap.pop()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let heap_items = self.heap.len();
match self.orig.size_hint() {
(lower, Some(upper)) => (
lower.saturating_add(heap_items),
Some(upper.saturating_add(heap_items)),
),
(lower, None) => (lower.saturating_add(heap_items), None),
}
}
}
pub fn window_sort<I: Iterator>(xs: I, window_size: usize) -> WindowSort<I>
where
<I as Iterator>::Item: Ord,
{
WindowSort {
orig: xs,
window_size,
heap: BinaryHeap::new(),
}
}
pub trait WindowSortIterExt: Sized {
fn window_sort(self, window_size: usize) -> WindowSort<Self>
where
Self: Iterator,
<Self as Iterator>::Item: Ord;
}
impl<I: Iterator> WindowSortIterExt for I
where
<I as Iterator>::Item: Ord,
{
fn window_sort(self, window_size: usize) -> WindowSort<Self> {
window_sort(self, window_size)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_sort_i32_fn() {
let a = &[3_i32, 4, 2, 1];
let mut it = window_sort(a.iter().cloned(), 2);
assert_eq!(Some(4), it.next());
assert_eq!(Some(3), it.next());
assert_eq!(Some(2), it.next());
assert_eq!(Some(1), it.next());
assert_eq!(None, it.next());
}
#[test]
fn should_sort_i32_method() {
let a = &[3_i32, 4, 2, 1];
let mut it = a.iter().cloned().window_sort(2);
assert_eq!(Some(4), it.next());
assert_eq!(Some(3), it.next());
assert_eq!(Some(2), it.next());
assert_eq!(Some(1), it.next());
assert_eq!(None, it.next());
}
#[test]
fn should_sort_window_only() {
let a = &[4_i32, 2, 1, 3];
let mut it = window_sort(a.iter().cloned(), 2);
assert_eq!(Some(4), it.next());
assert_eq!(Some(2), it.next());
assert_eq!(Some(3), it.next());
assert_eq!(Some(1), it.next());
assert_eq!(None, it.next());
}
#[test]
fn small_underlying_iterator() {
let a = &[2_i32, 3, 4, 1];
let mut it = window_sort(a.iter().cloned(), 10);
assert_eq!(Some(4), it.next());
assert_eq!(Some(3), it.next());
assert_eq!(Some(2), it.next());
assert_eq!(Some(1), it.next());
assert_eq!(None, it.next());
}
}