mirror of
https://github.com/typst/typst
synced 2025-08-14 23:18:32 +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.
|
/// determine the keys to sort by.
|
||||||
#[named]
|
#[named]
|
||||||
key: Option<Func>,
|
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> {
|
) -> SourceResult<Array> {
|
||||||
let mut result = Ok(());
|
let mut result = Ok(());
|
||||||
let mut vec = self.0;
|
let mut vec = self.0;
|
||||||
let mut key_of = |x: Value| match &key {
|
let mut compare = |x: Value, y: Value| {
|
||||||
// NOTE: We are relying on `comemo`'s memoization of function
|
let mut key_of = |x: Value| match &key {
|
||||||
// evaluation to not excessively reevaluate the `key`.
|
// NOTE: We are relying on `comemo`'s memoization of function
|
||||||
Some(f) => f.call(engine, context, [x]),
|
// evaluation to not excessively reevaluate the `key`.
|
||||||
None => Ok(x),
|
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| {
|
vec.make_mut().sort_by(|a, b| {
|
||||||
// Until we get `try` blocks :)
|
// Until we get `try` blocks :)
|
||||||
match (key_of(a.clone()), key_of(b.clone())) {
|
compare(a.clone(), b.clone()).unwrap_or_else(|err| {
|
||||||
(Ok(a), Ok(b)) => ops::compare(&a, &b).unwrap_or_else(|err| {
|
if result.is_ok() {
|
||||||
if result.is_ok() {
|
result = Err(err);
|
||||||
result = Err(err).at(span);
|
|
||||||
}
|
|
||||||
Ordering::Equal
|
|
||||||
}),
|
|
||||||
(Err(e), _) | (_, Err(e)) => {
|
|
||||||
if result.is_ok() {
|
|
||||||
result = Err(e);
|
|
||||||
}
|
|
||||||
Ordering::Equal
|
|
||||||
}
|
}
|
||||||
}
|
Ordering::Equal
|
||||||
|
})
|
||||||
});
|
});
|
||||||
result.map(|_| vec.into())
|
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(), (-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), (-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((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 ---
|
--- array-sorted-key-function-positional-1 ---
|
||||||
// Error: 12-18 unexpected argument
|
// Error: 12-18 unexpected argument
|
||||||
|
Loading…
x
Reference in New Issue
Block a user