mirror of
https://github.com/typst/typst
synced 2025-08-14 15:17:57 +08:00
Add compare argument for array.sorted
This commit is contained in:
parent
bb38a01d06
commit
c7216c26f5
@ -841,31 +841,42 @@ impl Array {
|
||||
/// determine the keys to sort by.
|
||||
#[named]
|
||||
key: Option<Func>,
|
||||
/// If given, uses this function to compare elements in the array to
|
||||
/// determine their relative order.
|
||||
#[named]
|
||||
compare: Option<Func>,
|
||||
) -> SourceResult<Array> {
|
||||
let mut result = Ok(());
|
||||
let mut vec = self.0;
|
||||
let mut key_of = |x: Value| match &key {
|
||||
// NOTE: We are relying on `comemo`'s memoization of function
|
||||
// evaluation to not excessively reevaluate the `key`.
|
||||
Some(f) => f.call(engine, context, [x]),
|
||||
None => Ok(x),
|
||||
let mut compare = |x: Value, y: Value| {
|
||||
let mut key_of = |x: Value| match &key {
|
||||
// NOTE: We are relying on `comemo`'s memoization of function
|
||||
// evaluation to not excessively reevaluate the `key`.
|
||||
Some(f) => f.call(engine, context, [x]),
|
||||
None => Ok(x),
|
||||
};
|
||||
let x = key_of(x)?;
|
||||
let y = key_of(y)?;
|
||||
match &compare {
|
||||
Some(f) => Ok(match f.call(engine, context, [x, y])? {
|
||||
Value::Int(x) => x.cmp(&0),
|
||||
x => bail!(
|
||||
span,
|
||||
"expected integer from `compare` function; got {}",
|
||||
x.repr()
|
||||
),
|
||||
}),
|
||||
None => ops::compare(&x, &y).at(span),
|
||||
}
|
||||
};
|
||||
vec.make_mut().sort_by(|a, b| {
|
||||
// Until we get `try` blocks :)
|
||||
match (key_of(a.clone()), key_of(b.clone())) {
|
||||
(Ok(a), Ok(b)) => ops::compare(&a, &b).unwrap_or_else(|err| {
|
||||
if result.is_ok() {
|
||||
result = Err(err).at(span);
|
||||
}
|
||||
Ordering::Equal
|
||||
}),
|
||||
(Err(e), _) | (_, Err(e)) => {
|
||||
if result.is_ok() {
|
||||
result = Err(e);
|
||||
}
|
||||
Ordering::Equal
|
||||
compare(a.clone(), b.clone()).unwrap_or_else(|err| {
|
||||
if result.is_ok() {
|
||||
result = Err(err);
|
||||
}
|
||||
}
|
||||
Ordering::Equal
|
||||
})
|
||||
});
|
||||
result.map(|_| vec.into())
|
||||
}
|
||||
|
@ -355,6 +355,8 @@
|
||||
#test((2, 1, 3, 10, 5, 8, 6, -7, 2).sorted(), (-7, 1, 2, 2, 3, 5, 6, 8, 10))
|
||||
#test((2, 1, 3, -10, -5, 8, 6, -7, 2).sorted(key: x => x), (-10, -7, -5, 1, 2, 2, 3, 6, 8))
|
||||
#test((2, 1, 3, -10, -5, 8, 6, -7, 2).sorted(key: x => x * x), (1, 2, 2, 3, -5, 6, -7, 8, -10))
|
||||
#test(("I", "the", "hi", "text").sorted(compare: (x, y) => x.len() - y.len()), ("I", "hi", "the", "text"))
|
||||
#test(("I", "the", "hi", "text").sorted(key: x => x.len(), compare: (x, y) => y - x), ("text", "the", "hi", "I"))
|
||||
|
||||
--- array-sorted-key-function-positional-1 ---
|
||||
// Error: 12-18 unexpected argument
|
||||
|
Loading…
x
Reference in New Issue
Block a user