use core::{cmp::Ordering, iter::Peekable}; pub struct MergeAscending where L: Iterator, R: Iterator, F: Fn(&R::Item) -> O, O: PartialOrd, { left: Peekable, right: Peekable, get_key: F, } impl MergeAscending where L: Iterator, R: Iterator, F: Fn(&R::Item) -> O, O: PartialOrd, { fn new(left: L, right: R, get_key: F) -> Self { MergeAscending { left: left.peekable(), right: right.peekable(), get_key, } } } impl Iterator for MergeAscending where L: Iterator, R: Iterator, F: Fn(&R::Item) -> O, O: PartialOrd, { type Item = L::Item; fn next(&mut self) -> Option { let order = match (self.left.peek(), self.right.peek()) { (Some(l), Some(r)) => (self.get_key)(l).partial_cmp(&(self.get_key)(r)), (Some(_), None) => Some(Ordering::Less), (None, Some(_)) => Some(Ordering::Greater), (None, None) => return None, }; match order { Some(Ordering::Less) | None => self.left.next(), Some(Ordering::Equal) => self.left.next(), Some(Ordering::Greater) => self.right.next(), } } } pub trait MergeSorted: Iterator { fn merge_sorted_by_key(self, other: R, get_key: F) -> MergeAscending where Self: Sized, R: Iterator, F: Fn(&Self::Item) -> O, O: PartialOrd, { MergeAscending::new(self, other, get_key) } } impl MergeSorted for T where T: Iterator {} #[cfg(test)] mod tests { use pretty_assertions::assert_eq; use super::*; #[test] fn test_merge_sorted_by_key() { let left = [9, 7, 5, 3, 1]; let right = [7, 6, 5, 4, 3]; let result: Vec = left .into_iter() .merge_sorted_by_key(right.into_iter(), |x| -1 * x) .collect(); assert_eq!(result, vec![9, 7, 7, 6, 5, 5, 4, 3, 3, 1]); } }