diff --git a/packages/@rescript/runtime/Stdlib_Array.res b/packages/@rescript/runtime/Stdlib_Array.res index 30dd573fd7b..e610826780e 100644 --- a/packages/@rescript/runtime/Stdlib_Array.res +++ b/packages/@rescript/runtime/Stdlib_Array.res @@ -346,6 +346,59 @@ let findMap = (arr, f) => { loop(0) } +let zip = (xs, ys) => { + let (lenx, leny) = (length(xs), length(ys)) + let len = min(lenx, leny) + let s = makeUninitializedUnsafe(len) + for i in 0 to len - 1 { + setUnsafe(s, i, (getUnsafe(xs, i), getUnsafe(ys, i))) + } + s +} + +let zipBy = (xs, ys, f) => { + let (lenx, leny) = (length(xs), length(ys)) + let len = min(lenx, leny) + let s = makeUninitializedUnsafe(len) + for i in 0 to len - 1 { + setUnsafe(s, i, f(getUnsafe(xs, i), getUnsafe(ys, i))) + } + s +} + +let partition = (a, f) => { + let l = length(a) + let i = ref(0) + let j = ref(0) + let a1 = makeUninitializedUnsafe(l) + let a2 = makeUninitializedUnsafe(l) + for ii in 0 to l - 1 { + let v = getUnsafe(a, ii) + if f(v) { + setUnsafe(a1, i.contents, v) + i.contents = i.contents + 1 + } else { + setUnsafe(a2, j.contents, v) + j.contents = j.contents + 1 + } + } + truncateToLengthUnsafe(a1, i.contents) + truncateToLengthUnsafe(a2, j.contents) + (a1, a2) +} + +let unzip = a => { + let l = length(a) + let a1 = makeUninitializedUnsafe(l) + let a2 = makeUninitializedUnsafe(l) + for i in 0 to l - 1 { + let (v1, v2) = getUnsafe(a, i) + setUnsafe(a1, i, v1) + setUnsafe(a2, i, v2) + } + (a1, a2) +} + @send external at: (array<'a>, int) => option<'a> = "at" let last = a => a->get(a->length - 1) diff --git a/packages/@rescript/runtime/Stdlib_Array.resi b/packages/@rescript/runtime/Stdlib_Array.resi index bdcb6086d94..3a0b69bf356 100644 --- a/packages/@rescript/runtime/Stdlib_Array.resi +++ b/packages/@rescript/runtime/Stdlib_Array.resi @@ -1555,6 +1555,61 @@ Array.findMap([], n => mod(n, 2) == 0 ? Some(n * n) : None) == None */ let findMap: (array<'a>, 'a => option<'b>) => option<'b> +/** +`zip(a, b)` create an array of pairs from corresponding elements of a and b. +Stop with the shorter array. + +## Examples + +```rescript +Array.zip([1, 2], [3, 4, 5]) == [(1, 3), (2, 4)] +``` +*/ +let zip: (t<'a>, array<'b>) => array<('a, 'b)> + +/** +`zipBy(xs, ys, f)` create an array by applying `f` to corresponding elements of +`xs` and `ys`. Stops with shorter array. + +Equivalent to `map(zip(xs, ys), ((a, b)) => f(a, b))` + +## Examples + +```rescript +Array.zipBy([1, 2, 3], [4, 5], (a, b) => 2 * a + b) == [6, 9] +``` +*/ +let zipBy: (t<'a>, array<'b>, ('a, 'b) => 'c) => array<'c> + +/** +`partition(f, a)` split array into tuple of two arrays based on predicate `f`; +first of tuple where predicate cause true, second where predicate cause false + +## Examples + +```rescript +Array.partition([1, 2, 3, 4, 5], x => mod(x, 2) == 0) == ([2, 4], [1, 3, 5]) + +Array.partition([1, 2, 3, 4, 5], x => mod(x, 2) != 0) == ([1, 3, 5], [2, 4]) +``` +*/ +let partition: (t<'a>, 'a => bool) => (t<'a>, t<'a>) + +/** +`unzip(a)` takes an array of pairs and creates a pair of arrays. The first array +contains all the first items of the pairs; the second array contains all the +second items. + +## Examples + +```rescript +Array.unzip([(1, 2), (3, 4)]) == ([1, 3], [2, 4]) + +Array.unzip([(1, 2), (3, 4), (5, 6), (7, 8)]) == ([1, 3, 5, 7], [2, 4, 6, 8]) +``` +*/ +let unzip: array<('a, 'b)> => (t<'a>, array<'b>) + /** `at(array, index)` diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_Array.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_Array.mjs index 455fe3a760f..c93b796b762 100644 --- a/packages/@rescript/runtime/lib/es6/Stdlib_Array.mjs +++ b/packages/@rescript/runtime/lib/es6/Stdlib_Array.mjs @@ -1,5 +1,6 @@ +import * as Primitive_int from "./Primitive_int.mjs"; import * as Primitive_option from "./Primitive_option.mjs"; function make(length, x) { @@ -189,6 +190,70 @@ function findMap(arr, f) { }; } +function zip(xs, ys) { + let lenx = xs.length; + let leny = ys.length; + let len = Primitive_int.min(lenx, leny); + let s = new Array(len); + for (let i = 0; i < len; ++i) { + s[i] = [ + xs[i], + ys[i] + ]; + } + return s; +} + +function zipBy(xs, ys, f) { + let lenx = xs.length; + let leny = ys.length; + let len = Primitive_int.min(lenx, leny); + let s = new Array(len); + for (let i = 0; i < len; ++i) { + s[i] = f(xs[i], ys[i]); + } + return s; +} + +function partition(a, f) { + let l = a.length; + let i = 0; + let j = 0; + let a1 = new Array(l); + let a2 = new Array(l); + for (let ii = 0; ii < l; ++ii) { + let v = a[ii]; + if (f(v)) { + a1[i] = v; + i = i + 1 | 0; + } else { + a2[j] = v; + j = j + 1 | 0; + } + } + a1.length = i; + a2.length = j; + return [ + a1, + a2 + ]; +} + +function unzip(a) { + let l = a.length; + let a1 = new Array(l); + let a2 = new Array(l); + for (let i = 0; i < l; ++i) { + let match = a[i]; + a1[i] = match[0]; + a2[i] = match[1]; + } + return [ + a1, + a2 + ]; +} + function last(a) { return a[a.length - 1 | 0]; } @@ -213,6 +278,10 @@ export { toShuffled, shuffle, findMap, + zip, + zipBy, + partition, + unzip, last, } /* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_Array.cjs b/packages/@rescript/runtime/lib/js/Stdlib_Array.cjs index 3d475134dc2..5d914379780 100644 --- a/packages/@rescript/runtime/lib/js/Stdlib_Array.cjs +++ b/packages/@rescript/runtime/lib/js/Stdlib_Array.cjs @@ -1,5 +1,6 @@ 'use strict'; +let Primitive_int = require("./Primitive_int.cjs"); let Primitive_option = require("./Primitive_option.cjs"); function make(length, x) { @@ -189,6 +190,70 @@ function findMap(arr, f) { }; } +function zip(xs, ys) { + let lenx = xs.length; + let leny = ys.length; + let len = Primitive_int.min(lenx, leny); + let s = new Array(len); + for (let i = 0; i < len; ++i) { + s[i] = [ + xs[i], + ys[i] + ]; + } + return s; +} + +function zipBy(xs, ys, f) { + let lenx = xs.length; + let leny = ys.length; + let len = Primitive_int.min(lenx, leny); + let s = new Array(len); + for (let i = 0; i < len; ++i) { + s[i] = f(xs[i], ys[i]); + } + return s; +} + +function partition(a, f) { + let l = a.length; + let i = 0; + let j = 0; + let a1 = new Array(l); + let a2 = new Array(l); + for (let ii = 0; ii < l; ++ii) { + let v = a[ii]; + if (f(v)) { + a1[i] = v; + i = i + 1 | 0; + } else { + a2[j] = v; + j = j + 1 | 0; + } + } + a1.length = i; + a2.length = j; + return [ + a1, + a2 + ]; +} + +function unzip(a) { + let l = a.length; + let a1 = new Array(l); + let a2 = new Array(l); + for (let i = 0; i < l; ++i) { + let match = a[i]; + a1[i] = match[0]; + a2[i] = match[1]; + } + return [ + a1, + a2 + ]; +} + function last(a) { return a[a.length - 1 | 0]; } @@ -212,5 +277,9 @@ exports.keepSome = keepSome; exports.toShuffled = toShuffled; exports.shuffle = shuffle; exports.findMap = findMap; +exports.zip = zip; +exports.zipBy = zipBy; +exports.partition = partition; +exports.unzip = unzip; exports.last = last; /* No side effect */ diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index 5b6d8ae3086..4b9a19ca990 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -178,6 +178,12 @@ Path Array. "tags": [], "detail": "(array<'a>, ~start: int=?, ~end: int=?) => array<'a>", "documentation": {"kind": "markdown", "value": "\n`slice(array, ~start, ~end)` creates a new array of items copied from `array` from `start` until (but not including) `end`.\n\nSee [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN.\n\n## Examples\n\n```rescript\n[1, 2, 3, 4]->Array.slice(~start=1, ~end=3) == [2, 3]\n[1, 2, 3, 4]->Array.slice(~start=1) == [2, 3, 4]\n[1, 2, 3, 4]->Array.slice == [1, 2, 3, 4]\n```\n"} + }, { + "label": "zip", + "kind": 12, + "tags": [], + "detail": "(t<'a>, array<'b>) => array<('a, 'b)>", + "documentation": {"kind": "markdown", "value": "\n`zip(a, b)` create an array of pairs from corresponding elements of a and b.\nStop with the shorter array.\n\n## Examples\n\n```rescript\nArray.zip([1, 2], [3, 4, 5]) == [(1, 3), (2, 4)]\n```\n"} }, { "label": "fillToEnd", "kind": 12, @@ -268,6 +274,12 @@ Path Array. "tags": [], "detail": "(array<'a>, 'a => 'b) => array<'b>", "documentation": {"kind": "markdown", "value": "\n`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray = array->Array.map(greeting => greeting ++ \" to you\")\n\nmappedArray == [\"Hello to you\", \"Hi to you\", \"Good bye to you\"]\n```\n"} + }, { + "label": "zipBy", + "kind": 12, + "tags": [], + "detail": "(t<'a>, array<'b>, ('a, 'b) => 'c) => array<'c>", + "documentation": {"kind": "markdown", "value": "\n`zipBy(xs, ys, f)` create an array by applying `f` to corresponding elements of\n`xs` and `ys`. Stops with shorter array.\n\nEquivalent to `map(zip(xs, ys), ((a, b)) => f(a, b))`\n\n## Examples\n\n```rescript\nArray.zipBy([1, 2, 3], [4, 5], (a, b) => 2 * a + b) == [6, 9]\n```\n"} }, { "label": "with", "kind": 12, @@ -538,6 +550,12 @@ Path Array. "tags": [1], "detail": "(array<'a>, int) => 'a", "documentation": {"kind": "markdown", "value": "Deprecated: \n\n\n`unsafe_get(array, index)` returns the element at `index` of `array`.\n\nThis is _unsafe_, meaning it will return `undefined` value if `index` does not exist in `array`.\n\nUse `Array.unsafe_get` only when you are sure the `index` exists (i.e. when using for-loop).\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3]\nfor index in 0 to array->Array.length - 1 {\n let value = array->Array.unsafe_get(index)\n Console.log(value)\n}\n```\n"} + }, { + "label": "partition", + "kind": 12, + "tags": [], + "detail": "(t<'a>, 'a => bool) => (t<'a>, t<'a>)", + "documentation": {"kind": "markdown", "value": "\n`partition(f, a)` split array into tuple of two arrays based on predicate `f`;\nfirst of tuple where predicate cause true, second where predicate cause false\n\n## Examples\n\n```rescript\nArray.partition([1, 2, 3, 4, 5], x => mod(x, 2) == 0) == ([2, 4], [1, 3, 5])\n\nArray.partition([1, 2, 3, 4, 5], x => mod(x, 2) != 0) == ([1, 3, 5], [2, 4])\n```\n"} }, { "label": "copyAllWithin", "kind": 12, @@ -586,6 +604,12 @@ Path Array. "tags": [], "detail": "(array<'a>, array<'a>) => unit", "documentation": {"kind": "markdown", "value": "\n`pushMany(array, itemsArray)` appends many new items to the end of the array.\n\nBeware this will *mutate* the array.\n\nSee [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\n\nsomeArray->Array.pushMany([\"yay\", \"wehoo\"])\nsomeArray == [\"hi\", \"hello\", \"yay\", \"wehoo\"]\n```\n"} + }, { + "label": "unzip", + "kind": 12, + "tags": [], + "detail": "array<('a, 'b)> => (t<'a>, array<'b>)", + "documentation": {"kind": "markdown", "value": "\n`unzip(a)` takes an array of pairs and creates a pair of arrays. The first array\ncontains all the first items of the pairs; the second array contains all the\nsecond items.\n\n## Examples\n\n```rescript\nArray.unzip([(1, 2), (3, 4)]) == ([1, 3], [2, 4])\n\nArray.unzip([(1, 2), (3, 4), (5, 6), (7, 8)]) == ([1, 3, 5, 7], [2, 4, 6, 8])\n```\n"} }, { "label": "fromIterator", "kind": 12, diff --git a/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt b/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt index 233a6ab806b..d8ab393512e 100644 --- a/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt +++ b/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt @@ -270,6 +270,18 @@ Path u "range": {"start": {"line": 75, "character": 7}, "end": {"line": 75, "character": 8}}, "newText": "" }] + }, { + "label": "->Array.unzip", + "kind": 12, + "tags": [], + "detail": "array<('a, 'b)> => (t<'a>, array<'b>)", + "documentation": {"kind": "markdown", "value": "\n`unzip(a)` takes an array of pairs and creates a pair of arrays. The first array\ncontains all the first items of the pairs; the second array contains all the\nsecond items.\n\n## Examples\n\n```rescript\nArray.unzip([(1, 2), (3, 4)]) == ([1, 3], [2, 4])\n\nArray.unzip([(1, 2), (3, 4), (5, 6), (7, 8)]) == ([1, 3, 5, 7], [2, 4, 6, 8])\n```\n"}, + "sortText": "unzip", + "insertText": "->Array.unzip", + "additionalTextEdits": [{ + "range": {"start": {"line": 75, "character": 7}, "end": {"line": 75, "character": 8}}, + "newText": "" + }] }] Complete src/DotPipeCompletionSpec.res 80:7