Skip to content

Commit e8c67ef

Browse files
zayenzphimuemue
authored andcommitted
FEAT: Add {min,max}_set(_by{_key)?)? functions
The function min_set returns a Vec of all the minimum values. All variants for max and with key extraction and comparison functions are added also. Since the functions need to return an unknown number of values and the values are not known until the iterator is finished, the function needs to allocate memory. Therefore Vec is used for returning the values.
1 parent 8e73e5d commit e8c67ef

File tree

3 files changed

+280
-0
lines changed

3 files changed

+280
-0
lines changed

src/extrema_set.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/// Implementation guts for `min_set`, `min_set_by`, and `min_set_by_key`.
2+
pub fn min_set_impl<I, K, F, L>(mut it: I,
3+
mut key_for: F,
4+
mut lt: L) -> Option<Vec<I::Item>>
5+
where I: Iterator,
6+
F: FnMut(&I::Item) -> K,
7+
L: FnMut(&I::Item, &I::Item, &K, &K) -> bool,
8+
{
9+
let (mut result, mut current_key) = match it.next() {
10+
None => return None,
11+
Some(element) => {
12+
let key = key_for(&element);
13+
(vec![element], key)
14+
}
15+
};
16+
17+
for element in it {
18+
let key = key_for(&element);
19+
if lt(&element, &result[0], &key, &current_key) {
20+
result.clear();
21+
result.push(element);
22+
current_key = key;
23+
} else if !lt(&result[0], &element, &current_key, &key) {
24+
result.push(element);
25+
}
26+
}
27+
28+
Some(result)
29+
}
30+
31+
/// Implementation guts for `ax_set`, `max_set_by`, and `max_set_by_key`.
32+
pub fn max_set_impl<I, K, F, L>(it: I,
33+
key_for: F,
34+
mut lt: L) -> Option<Vec<I::Item>>
35+
where I: Iterator,
36+
F: FnMut(&I::Item) -> K,
37+
L: FnMut(&I::Item, &I::Item, &K, &K) -> bool,
38+
{
39+
min_set_impl(it, key_for, |it1, it2, key1, key2| lt(it2, it1, key2, key1))
40+
}
41+
42+

src/lib.rs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ mod combinations_with_replacement;
197197
mod exactly_one_err;
198198
mod diff;
199199
mod flatten_ok;
200+
#[cfg(feature = "use_std")]
201+
mod extrema_set;
200202
mod format;
201203
#[cfg(feature = "use_std")]
202204
mod grouping_map;
@@ -2902,6 +2904,194 @@ pub trait Itertools : Iterator {
29022904
grouping_map::new(grouping_map::MapForGrouping::new(self, key_mapper))
29032905
}
29042906

2907+
/// Return all minimum elements of an iterator.
2908+
///
2909+
/// # Examples
2910+
///
2911+
/// ```
2912+
/// use itertools::Itertools;
2913+
///
2914+
/// let a: [i32; 0] = [];
2915+
/// assert_eq!(a.iter().min_set(), None);
2916+
///
2917+
/// let a = [1];
2918+
/// assert_eq!(a.iter().min_set(), Some(vec![&1]));
2919+
///
2920+
/// let a = [1, 2, 3, 4, 5];
2921+
/// assert_eq!(a.iter().min_set(), Some(vec![&1]));
2922+
///
2923+
/// let a = [1, 1, 1, 1];
2924+
/// assert_eq!(a.iter().min_set(), Some(vec![&1, &1, &1, &1]));
2925+
/// ```
2926+
///
2927+
/// The elements can be floats but no particular result is guaranteed
2928+
/// if an element is NaN.
2929+
#[cfg(feature = "use_std")]
2930+
fn min_set(self) -> Option<Vec<Self::Item>>
2931+
where Self: Sized, Self::Item: PartialOrd
2932+
{
2933+
extrema_set::min_set_impl(self, |_| (), |x, y, _, _| x < y)
2934+
}
2935+
2936+
/// Return all minimum elements of an iterator, as determined by
2937+
/// the specified function.
2938+
///
2939+
/// # Examples
2940+
///
2941+
/// ```
2942+
/// # use std::cmp::Ordering;
2943+
/// use itertools::Itertools;
2944+
///
2945+
/// let a: [(i32, i32); 0] = [];
2946+
/// assert_eq!(a.iter().min_set_by(|_, _| Ordering::Equal), None);
2947+
///
2948+
/// let a = [(1, 2)];
2949+
/// assert_eq!(a.iter().min_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), Some(vec![&(1, 2)]));
2950+
///
2951+
/// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
2952+
/// assert_eq!(a.iter().min_set_by(|&&(_,k1), &&(_,k2)| k1.cmp(&k2)), Some(vec![&(1, 2), &(2, 2)]));
2953+
///
2954+
/// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
2955+
/// assert_eq!(a.iter().min_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), Some(vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]));
2956+
/// ```
2957+
///
2958+
/// The elements can be floats but no particular result is guaranteed
2959+
/// if an element is NaN.
2960+
#[cfg(feature = "use_std")]
2961+
fn min_set_by<F>(self, mut compare: F) -> Option<Vec<Self::Item>>
2962+
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering
2963+
{
2964+
extrema_set::min_set_impl(
2965+
self,
2966+
|_| (),
2967+
|x, y, _, _| Ordering::Less == compare(x, y)
2968+
)
2969+
}
2970+
2971+
/// Return all minimum elements of an iterator, as determined by
2972+
/// the specified function.
2973+
///
2974+
/// # Examples
2975+
///
2976+
/// ```
2977+
/// use itertools::Itertools;
2978+
///
2979+
/// let a: [(i32, i32); 0] = [];
2980+
/// assert_eq!(a.iter().min_set_by_key(|_| ()), None);
2981+
///
2982+
/// let a = [(1, 2)];
2983+
/// assert_eq!(a.iter().min_set_by_key(|&&(k,_)| k), Some(vec![&(1, 2)]));
2984+
///
2985+
/// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
2986+
/// assert_eq!(a.iter().min_set_by_key(|&&(_, k)| k), Some(vec![&(1, 2), &(2, 2)]));
2987+
///
2988+
/// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
2989+
/// assert_eq!(a.iter().min_set_by_key(|&&(k, _)| k), Some(vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]));
2990+
/// ```
2991+
///
2992+
/// The elements can be floats but no particular result is guaranteed
2993+
/// if an element is NaN.
2994+
#[cfg(feature = "use_std")]
2995+
fn min_set_by_key<K, F>(self, key: F) -> Option<Vec<Self::Item>>
2996+
where Self: Sized, K: PartialOrd, F: FnMut(&Self::Item) -> K
2997+
{
2998+
extrema_set::min_set_impl(self, key, |_, _, kx, ky| kx < ky)
2999+
}
3000+
3001+
/// Return all maximum elements of an iterator.
3002+
///
3003+
/// # Examples
3004+
///
3005+
/// ```
3006+
/// use itertools::Itertools;
3007+
///
3008+
/// let a: [i32; 0] = [];
3009+
/// assert_eq!(a.iter().max_set(), None);
3010+
///
3011+
/// let a = [1];
3012+
/// assert_eq!(a.iter().max_set(), Some(vec![&1]));
3013+
///
3014+
/// let a = [1, 2, 3, 4, 5];
3015+
/// assert_eq!(a.iter().max_set(), Some(vec![&5]));
3016+
///
3017+
/// let a = [1, 1, 1, 1];
3018+
/// assert_eq!(a.iter().max_set(), Some(vec![&1, &1, &1, &1]));
3019+
/// ```
3020+
///
3021+
/// The elements can be floats but no particular result is guaranteed
3022+
/// if an element is NaN.
3023+
#[cfg(feature = "use_std")]
3024+
fn max_set(self) -> Option<Vec<Self::Item>>
3025+
where Self: Sized, Self::Item: PartialOrd
3026+
{
3027+
extrema_set::max_set_impl(self, |_| (), |x, y, _, _| x < y)
3028+
}
3029+
3030+
/// Return all maximum elements of an iterator, as determined by
3031+
/// the specified function.
3032+
///
3033+
/// # Examples
3034+
///
3035+
/// ```
3036+
/// # use std::cmp::Ordering;
3037+
/// use itertools::Itertools;
3038+
///
3039+
/// let a: [(i32, i32); 0] = [];
3040+
/// assert_eq!(a.iter().max_set_by(|_, _| Ordering::Equal), None);
3041+
///
3042+
/// let a = [(1, 2)];
3043+
/// assert_eq!(a.iter().max_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), Some(vec![&(1, 2)]));
3044+
///
3045+
/// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
3046+
/// assert_eq!(a.iter().max_set_by(|&&(_,k1), &&(_,k2)| k1.cmp(&k2)), Some(vec![&(3, 9), &(5, 9)]));
3047+
///
3048+
/// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
3049+
/// assert_eq!(a.iter().max_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), Some(vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]));
3050+
/// ```
3051+
///
3052+
/// The elements can be floats but no particular result is guaranteed
3053+
/// if an element is NaN.
3054+
#[cfg(feature = "use_std")]
3055+
fn max_set_by<F>(self, mut compare: F) -> Option<Vec<Self::Item>>
3056+
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering
3057+
{
3058+
extrema_set::max_set_impl(
3059+
self,
3060+
|_| (),
3061+
|x, y, _, _| Ordering::Less == compare(x, y)
3062+
)
3063+
}
3064+
3065+
/// Return all minimum elements of an iterator, as determined by
3066+
/// the specified function.
3067+
///
3068+
/// # Examples
3069+
///
3070+
/// ```
3071+
/// use itertools::Itertools;
3072+
///
3073+
/// let a: [(i32, i32); 0] = [];
3074+
/// assert_eq!(a.iter().max_set_by_key(|_| ()), None);
3075+
///
3076+
/// let a = [(1, 2)];
3077+
/// assert_eq!(a.iter().max_set_by_key(|&&(k,_)| k), Some(vec![&(1, 2)]));
3078+
///
3079+
/// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
3080+
/// assert_eq!(a.iter().max_set_by_key(|&&(_, k)| k), Some(vec![&(3, 9), &(5, 9)]));
3081+
///
3082+
/// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
3083+
/// assert_eq!(a.iter().max_set_by_key(|&&(k, _)| k), Some(vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]));
3084+
/// ```
3085+
///
3086+
/// The elements can be floats but no particular result is guaranteed
3087+
/// if an element is NaN.
3088+
#[cfg(feature = "use_std")]
3089+
fn max_set_by_key<K, F>(self, key: F) -> Option<Vec<Self::Item>>
3090+
where Self: Sized, K: PartialOrd, F: FnMut(&Self::Item) -> K
3091+
{
3092+
extrema_set::max_set_impl(self, key, |_, _, kx, ky| kx < ky)
3093+
}
3094+
29053095
/// Return the minimum and maximum elements in the iterator.
29063096
///
29073097
/// The return type `MinMaxResult` is an enum of three variants:

tests/test_std.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,54 @@ fn diff_shorter() {
992992
});
993993
}
994994

995+
#[test]
996+
fn extrema_set() {
997+
use std::cmp::Ordering;
998+
999+
// A peculiar type: Equality compares both tuple items, but ordering only the
1000+
// first item. Used to distinguish equal elements.
1001+
#[derive(Clone, Debug, PartialEq, Eq)]
1002+
struct Val(u32, u32);
1003+
1004+
impl PartialOrd<Val> for Val {
1005+
fn partial_cmp(&self, other: &Val) -> Option<Ordering> {
1006+
self.0.partial_cmp(&other.0)
1007+
}
1008+
}
1009+
1010+
impl Ord for Val {
1011+
fn cmp(&self, other: &Val) -> Ordering {
1012+
self.0.cmp(&other.0)
1013+
}
1014+
}
1015+
1016+
assert_eq!(None::<Option<u32>>.iter().min_set(), None);
1017+
assert_eq!(None::<Option<u32>>.iter().max_set(), None);
1018+
1019+
assert_eq!(Some(1u32).iter().min_set(), Some(vec![&1]));
1020+
assert_eq!(Some(1u32).iter().max_set(), Some(vec![&1]));
1021+
1022+
let data = vec![Val(0, 1), Val(2, 0), Val(0, 2), Val(1, 0), Val(2, 1)];
1023+
1024+
let min_set = data.iter().min_set().unwrap();
1025+
assert_eq!(min_set, vec![&Val(0, 1), &Val(0, 2)]);
1026+
1027+
let min_set_by_key = data.iter().min_set_by_key(|v| v.1).unwrap();
1028+
assert_eq!(min_set_by_key, vec![&Val(2, 0), &Val(1, 0)]);
1029+
1030+
let min_set_by = data.iter().min_set_by(|x, y| x.1.cmp(&y.1)).unwrap();
1031+
assert_eq!(min_set_by, vec![&Val(2, 0), &Val(1, 0)]);
1032+
1033+
let max_set = data.iter().max_set().unwrap();
1034+
assert_eq!(max_set, vec![&Val(2, 0), &Val(2, 1)]);
1035+
1036+
let max_set_by_key = data.iter().max_set_by_key(|v| v.1).unwrap();
1037+
assert_eq!(max_set_by_key, vec![&Val(0, 2)]);
1038+
1039+
let max_set_by = data.iter().max_set_by(|x, y| x.1.cmp(&y.1)).unwrap();
1040+
assert_eq!(max_set_by, vec![&Val(0, 2)]);
1041+
}
1042+
9951043
#[test]
9961044
fn minmax() {
9971045
use std::cmp::Ordering;

0 commit comments

Comments
 (0)