diff options
| author | Sébastien d'Herbais de Thun <sebastien.d.herbais@gmail.com> | 2023-07-18 15:23:56 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-07-18 15:23:56 +0200 |
| commit | 0c94d2b34e77edbd116c9f7be591ca710363b844 (patch) | |
| tree | af93fac42444953d8a744bcd3f68300c1dc7fef3 /crates | |
| parent | e43903d625f1009befe4f2341e52a720d657ad05 (diff) | |
Adding `dedup` to `array` (#1738)
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/typst/src/eval/array.rs | 32 | ||||
| -rw-r--r-- | crates/typst/src/eval/methods.rs | 1 |
2 files changed, 33 insertions, 0 deletions
diff --git a/crates/typst/src/eval/array.rs b/crates/typst/src/eval/array.rs index a7a1387b..5d5fdcdb 100644 --- a/crates/typst/src/eval/array.rs +++ b/crates/typst/src/eval/array.rs @@ -398,6 +398,38 @@ impl Array { .map(|(i, value)| array![i, value.clone()].into_value()) .collect() } + + /// Deduplicates all items in the array. + pub fn dedup(&self, vm: &mut Vm, key: Option<Func>) -> SourceResult<Self> { + let mut out = EcoVec::with_capacity(self.0.len()); + 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_vm(vm, Args::new(f.span(), [x])), + None => Ok(x), + }; + + // This algorithm is O(N^2) because we cannot rely on `HashSet` since: + // 1. We would like to preserve the order of the elements. + // 2. We cannot hash arbitrary `Value`. + 'outer: for value in self.iter() { + let key = key_of(value.clone())?; + if out.is_empty() { + out.push(value.clone()); + continue; + } + + for second in out.iter() { + if typst::eval::ops::equal(&key, &key_of(second.clone())?) { + continue 'outer; + } + } + + out.push(value.clone()); + } + + Ok(Self(out)) + } } impl Debug for Array { diff --git a/crates/typst/src/eval/methods.rs b/crates/typst/src/eval/methods.rs index a7368426..bf47b7aa 100644 --- a/crates/typst/src/eval/methods.rs +++ b/crates/typst/src/eval/methods.rs @@ -147,6 +147,7 @@ pub fn call( "sorted" => array.sorted(vm, span, args.named("key")?)?.into_value(), "zip" => array.zip(args.expect("other")?).into_value(), "enumerate" => array.enumerate().into_value(), + "dedup" => array.dedup(vm, args.named("key")?)?.into_value(), _ => return missing(), }, |
