diff --git a/docs/src/reference/types.md b/docs/src/reference/types.md index 24756422b..1bae6b752 100644 --- a/docs/src/reference/types.md +++ b/docs/src/reference/types.md @@ -620,6 +620,16 @@ for loop. - returns: array +### zip() +Zips the array with another array. If the two arrays are of unequal length, it +will only zip up until the last element of the smaller array and the remaining +elements will be ignored. The return value is an array where each element is yet +another array of size 2. + +- other: array (positional, required) + The other array which should be zipped with the current one. +- returns: array + ### fold() Folds all items into a single value using an accumulator function. diff --git a/src/eval/array.rs b/src/eval/array.rs index 1166ce949..f6e2f2d4e 100644 --- a/src/eval/array.rs +++ b/src/eval/array.rs @@ -306,6 +306,18 @@ impl Array { Ok(result) } + /// Zips the array with another array. If the two arrays are of unequal length, it will only + /// zip up until the last element of the smaller array and the remaining elements will be + /// ignored. The return value is an array where each element is yet another array of size 2. + pub fn zip(&self, other: Array) -> Array { + self.iter() + .zip(other) + .map(|(first, second)| { + Value::Array(Array::from_vec(eco_vec![first.clone(), second])) + }) + .collect() + } + /// Return a sorted version of this array, optionally by a given key function. /// /// Returns an error if two values could not be compared or if the key function (if given) diff --git a/src/eval/methods.rs b/src/eval/methods.rs index 29b729cbe..3ee4599c2 100644 --- a/src/eval/methods.rs +++ b/src/eval/methods.rs @@ -118,6 +118,7 @@ pub fn call( array.join(sep, last).at(span)? } "sorted" => Value::Array(array.sorted(vm, span, args.named("key")?)?), + "zip" => Value::Array(array.zip(args.expect("other")?)), "enumerate" => Value::Array(array.enumerate()), _ => return missing(), }, @@ -319,6 +320,7 @@ pub fn methods_on(type_name: &str) -> &[(&'static str, bool)] { ("slice", true), ("sorted", false), ("enumerate", false), + ("zip", true), ], "dictionary" => &[ ("at", true), diff --git a/tests/typ/compiler/array.typ b/tests/typ/compiler/array.typ index c52160b08..5d7e8b63c 100644 --- a/tests/typ/compiler/array.typ +++ b/tests/typ/compiler/array.typ @@ -223,6 +223,17 @@ #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 the `zip` method. +#test(().zip(()), ()) +#test((1,).zip(()), ()) +#test((1,).zip((2,)), ((1, 2),)) +#test((1, 2).zip((3, 4)), ((1, 3), (2, 4))) +#test((1, 2, 3, 4).zip((5, 6)), ((1, 5), (2, 6))) +#test(((1, 2), 3).zip((4, 5)), (((1, 2), 4), (3, 5))) +#test((1, "hi").zip((true, false)), ((1, true), ("hi", false))) + + --- // Error: 32-37 cannot divide by zero #(1, 2, 0, 3).sorted(key: x => 5 / x)