Skip to content

Commit c7c4d47

Browse files
authored
πŸ”‘ added max_by_key (#73)
1 parent 3c1b14c commit c7c4d47

5 files changed

Lines changed: 83 additions & 0 deletions

File tree

β€Žndc_lib/src/stdlib/sequence.rsβ€Ž

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,33 @@ mod inner {
111111
Sequence::Deque(d) => d.try_borrow()?.iter().try_max(),
112112
}
113113
}
114+
/// Returns the element for which the key function returns the highest value.
115+
pub fn max_by_key(seq: &mut Sequence, func: &Callable<'_>) -> EvaluationResult {
116+
by_key(seq, func, Ordering::Greater)
117+
}
118+
119+
/// Returns the element for which the key function returns the lowest value.
120+
pub fn min_by_key(seq: &mut Sequence, func: &Callable<'_>) -> EvaluationResult {
121+
by_key(seq, func, Ordering::Less)
122+
}
123+
124+
/// Returns the maximum element using a comparator function.
125+
///
126+
/// The comparator function takes two elements and returns a number. A positive result means the
127+
/// first argument is greater than the second, a negative result means the first argument is
128+
/// less than the second, and zero means they are equal.
129+
pub fn max_by(seq: &mut Sequence, comp: &Callable<'_>) -> EvaluationResult {
130+
by_comp(seq, comp, Ordering::Greater)
131+
}
132+
133+
/// Returns the minimum element using a comparator function.
134+
///
135+
/// The comparator function takes two elements and returns a number. A positive result means the
136+
/// first argument is greater than the second, a negative result means the first argument is
137+
/// less than the second, and zero means they are equal.
138+
pub fn min_by(seq: &mut Sequence, comp: &Callable<'_>) -> EvaluationResult {
139+
by_comp(seq, comp, Ordering::Less)
140+
}
114141

115142
/// Returns the lowest element in the sequence.
116143
pub fn min(seq: &Sequence) -> anyhow::Result<Value> {
@@ -750,6 +777,52 @@ mod inner {
750777
}
751778
}
752779

780+
fn by_key(
781+
seq: &mut Sequence,
782+
func: &Callable<'_>,
783+
better: Ordering,
784+
) -> EvaluationResult {
785+
let mut best_value = None;
786+
let mut best_key: Option<Value> = None;
787+
788+
for value in mut_seq_to_iterator(seq) {
789+
let new_key = func.call(&mut [value.clone()])?;
790+
let is_better = match &best_key {
791+
None => true,
792+
Some(current_best) => new_key.try_cmp(current_best)? == better,
793+
};
794+
if is_better {
795+
best_key = Some(new_key);
796+
best_value = Some(value);
797+
}
798+
}
799+
800+
best_value.ok_or_else(|| anyhow::anyhow!("sequence was empty").into())
801+
}
802+
803+
fn by_comp(
804+
seq: &mut Sequence,
805+
comp: &Callable<'_>,
806+
better: Ordering,
807+
) -> EvaluationResult {
808+
let mut best: Option<Value> = None;
809+
810+
for value in mut_seq_to_iterator(seq) {
811+
let is_better = match &best {
812+
None => true,
813+
Some(current) => {
814+
let result = comp.call(&mut [value.clone(), current.clone()])?;
815+
result.try_cmp(&Value::from(0))? == better
816+
}
817+
};
818+
if is_better {
819+
best = Some(value);
820+
}
821+
}
822+
823+
best.ok_or_else(|| anyhow::anyhow!("sequence was empty").into())
824+
}
825+
753826
fn fold_iterator(
754827
iterator: MutableValueIntoIterator<'_>,
755828
initial: Value,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
assert_eq([3, 1, 4, 1, 5, 9].max_by_key(fn(x) => x), 9);
2+
assert_eq(["foo", "ba", "quux"].max_by_key(fn(s) => s.len()), "quux");
3+
assert_eq([(1, 10), (2, 5), (3, 8)].max_by_key(fn(t) => t[1]), (1, 10));
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
assert_eq([3, 1, 4, 1, 5, 9].min_by_key(fn(x) => x), 1);
2+
assert_eq(["foo", "ba", "quux"].min_by_key(fn(s) => s.len()), "ba");
3+
assert_eq([(1, 10), (2, 5), (3, 8)].min_by_key(fn(t) => t[1]), (2, 5));
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
assert_eq([3, 1, 4, 1, 5, 9].max_by(fn(a, b) => a <=> b), 9);
2+
assert_eq(["foo", "ba", "quux"].max_by(fn(a, b) => a.len() <=> b.len()), "quux");
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
assert_eq([3, 1, 4, 1, 5, 9].min_by(fn(a, b) => a <=> b), 1);
2+
assert_eq(["foo", "ba", "quux"].min_by(fn(a, b) => a.len() <=> b.len()), "ba");

0 commit comments

Comments
Β (0)