Skip to content

Commit 021682a

Browse files
authored
Add Array.findLast and Array.findLastIndex bindings (#7503)
* Add `Array.findLast`, `Array.findLastWithIndex`, `Array.findLastIndex`, `Array.findLastIndexWithIndex` and `Array.findLastIndexOpt` bindings * Add `TypedArray.findLast`, `TypedArray.findLastWithIndex`, `TypedArray.findLastIndex` and `TypedArray.findLastIndexWithIndex` * Add CHANGELOG * Update expected completions
1 parent 2193869 commit 021682a

File tree

7 files changed

+171
-0
lines changed

7 files changed

+171
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#### :rocket: New Feature
1616

1717
- Add `RegExp.flags`. https://github.com/rescript-lang/rescript/pull/7461
18+
- Add `Array.findLast`, `Array.findLastWithIndex`, `Array.findLastIndex`, `Array.findLastIndexWithIndex` and `Array.findLastIndexOpt`. https://github.com/rescript-lang/rescript/pull/7503
1819

1920
#### :bug: Bug fix
2021

lib/es6/Stdlib_Array.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ function findIndexOpt(array, finder) {
106106

107107
}
108108

109+
function findLastIndexOpt(array, finder) {
110+
let index = array.findLastIndex(finder);
111+
if (index !== -1) {
112+
return index;
113+
}
114+
115+
}
116+
109117
function swapUnsafe(xs, i, j) {
110118
let tmp = xs[i];
111119
xs[i] = xs[j];
@@ -182,6 +190,7 @@ export {
182190
reduceRight,
183191
reduceRightWithIndex,
184192
findIndexOpt,
193+
findLastIndexOpt,
185194
filterMap,
186195
keepSome,
187196
toShuffled,

lib/js/Stdlib_Array.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ function findIndexOpt(array, finder) {
106106

107107
}
108108

109+
function findLastIndexOpt(array, finder) {
110+
let index = array.findLastIndex(finder);
111+
if (index !== -1) {
112+
return index;
113+
}
114+
115+
}
116+
109117
function swapUnsafe(xs, i, j) {
110118
let tmp = xs[i];
111119
xs[i] = xs[j];
@@ -181,6 +189,7 @@ exports.reduceWithIndex = reduceWithIndex;
181189
exports.reduceRight = reduceRight;
182190
exports.reduceRightWithIndex = reduceRightWithIndex;
183191
exports.findIndexOpt = findIndexOpt;
192+
exports.findLastIndexOpt = findLastIndexOpt;
184193
exports.filterMap = filterMap;
185194
exports.keepSome = keepSome;
186195
exports.toShuffled = toShuffled;

runtime/Stdlib_Array.res

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,15 @@ let lastIndexOfOpt = (arr, item) =>
169169
@send external find: (array<'a>, 'a => bool) => option<'a> = "find"
170170
@send external findWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "find"
171171

172+
@send external findLast: (t<'a>, 'a => bool) => option<'a> = "findLast"
173+
@send external findLastWithIndex: (t<'a>, ('a, int) => bool) => option<'a> = "findLast"
174+
172175
@send external findIndex: (array<'a>, 'a => bool) => int = "findIndex"
173176
@send external findIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findIndex"
174177

178+
@send external findLastIndex: (t<'a>, 'a => bool) => int = "findLastIndex"
179+
@send external findLastIndexWithIndex: (t<'a>, ('a, int) => bool) => int = "findLastIndex"
180+
175181
@send external forEach: (array<'a>, 'a => unit) => unit = "forEach"
176182
@send external forEachWithIndex: (array<'a>, ('a, int) => unit) => unit = "forEach"
177183

@@ -205,6 +211,12 @@ let findIndexOpt = (array: array<'a>, finder: 'a => bool): option<int> =>
205211
| index => Some(index)
206212
}
207213

214+
let findLastIndexOpt = (array: array<'a>, finder: 'a => bool): option<int> =>
215+
switch findLastIndex(array, finder) {
216+
| -1 => None
217+
| index => Some(index)
218+
}
219+
208220
let swapUnsafe = (xs, i, j) => {
209221
let tmp = getUnsafe(xs, i)
210222
setUnsafe(xs, i, getUnsafe(xs, j))

runtime/Stdlib_Array.resi

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,42 @@ array
720720
@send
721721
external findWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "find"
722722

723+
/**
724+
`findLast(array, checker)` returns the last element of `array` where the provided `checker` function returns true.
725+
726+
See [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN.
727+
728+
## Examples
729+
730+
```rescript
731+
let array = [1, 2, 3]
732+
733+
array
734+
->Array.findLast(item => item > 0)
735+
->assertEqual(Some(3))
736+
```
737+
*/
738+
@send
739+
external findLast: (array<'a>, 'a => bool) => option<'a> = "findLast"
740+
741+
/**
742+
`findLastWithIndex(array, checker)` returns the last element of `array` where the provided `checker` function returns true.
743+
744+
See [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN.
745+
746+
## Examples
747+
748+
```rescript
749+
let array = [1, 2, 3]
750+
751+
array
752+
->Array.findLastWithIndex((item, index) => index < 2 && item > 0)
753+
->assertEqual(Some(2))
754+
```
755+
*/
756+
@send
757+
external findLastWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "findLast"
758+
723759
/**
724760
`findIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true.
725761
@@ -769,6 +805,55 @@ assertEqual(isTypeScriptFirst, -1)
769805
@send
770806
external findIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findIndex"
771807

808+
/**
809+
`findLastIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.
810+
811+
Returns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`).
812+
813+
See [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.
814+
815+
## Examples
816+
817+
```rescript
818+
type languages = ReScript | TypeScript | JavaScript
819+
820+
let array = [ReScript, JavaScript, ReScript]
821+
822+
array
823+
->Array.findLastIndex(item => item == ReScript)
824+
->assertEqual(2)
825+
826+
array->Array.findLastIndex(item => item == TypeScript)
827+
->assertEqual(-1)
828+
```
829+
*/
830+
@send
831+
external findLastIndex: (array<'a>, 'a => bool) => int = "findLastIndex"
832+
833+
/**
834+
`findLastIndexWithIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.
835+
836+
Returns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`).
837+
838+
See [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.
839+
840+
## Examples
841+
842+
```rescript
843+
type languages = ReScript | TypeScript | JavaScript
844+
845+
let array = [ReScript, JavaScript, JavaScript, ReScript]
846+
847+
let isReScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == ReScript)
848+
let isTypeScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == TypeScript)
849+
850+
assertEqual(isReScriptLast, 3)
851+
assertEqual(isTypeScriptLast, -1)
852+
```
853+
*/
854+
@send
855+
external findLastIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findLastIndex"
856+
772857
/**
773858
`forEach(array, fn)` runs the provided `fn` on every element of `array`.
774859
@@ -1064,6 +1149,25 @@ array
10641149
*/
10651150
let findIndexOpt: (array<'a>, 'a => bool) => option<int>
10661151

1152+
/**
1153+
`findIndexOpt(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.
1154+
1155+
Returns `None` if no item matches.
1156+
1157+
See [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.
1158+
1159+
## Examples
1160+
1161+
```rescript
1162+
let array = ["hello", "world", "!"]
1163+
1164+
array
1165+
->Array.findLastIndexOpt(item => item->String.includes("o"))
1166+
->assertEqual(Some(1))
1167+
```
1168+
*/
1169+
let findLastIndexOpt: (array<'a>, 'a => bool) => option<int>
1170+
10671171
/**
10681172
`toReversed(array)` creates a new array with all items from `array` in reversed order.
10691173

runtime/Stdlib_TypedArray.res

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,15 @@ external copyWithin: (t<'a>, ~target: int, ~start: int, ~end: int) => array<'a>
5959
@send external find: (t<'a>, 'a => bool) => option<'a> = "find"
6060
@send external findWithIndex: (t<'a>, ('a, int) => bool) => option<'a> = "find"
6161

62+
@send external findLast: (t<'a>, 'a => bool) => option<'a> = "findLast"
63+
@send external findLastWithIndex: (t<'a>, ('a, int) => bool) => option<'a> = "findLast"
64+
6265
@send external findIndex: (t<'a>, 'a => bool) => int = "findIndex"
6366
@send external findIndexWithIndex: (t<'a>, ('a, int) => bool) => int = "findIndex"
6467

68+
@send external findLastIndex: (t<'a>, 'a => bool) => int = "findLastIndex"
69+
@send external findLastIndexWithIndex: (t<'a>, ('a, int) => bool) => int = "findLastIndex"
70+
6571
@send external forEach: (t<'a>, 'a => unit) => unit = "forEach"
6672
@send external forEachWithIndex: (t<'a>, ('a, int) => unit) => unit = "forEach"
6773

tests/analysis_tests/tests/src/expected/Completion.res.txt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ Path Array.
6464
"tags": [],
6565
"detail": "(array<'a>, 'a => option<'b>) => array<'b>",
6666
"documentation": {"kind": "markdown", "value": "\n`filterMap(array, fn)`\n\nCalls `fn` for each element and returns a new array containing results of the `fn` calls which are not `None`.\n\n## Examples\n\n```rescript\n[\"Hello\", \"Hi\", \"Good bye\"]\n->Array.filterMap(item =>\n switch item {\n | \"Hello\" => Some(item->String.length)\n | _ => None\n }\n)\n->assertEqual([5])\n\n[1, 2, 3, 4, 5, 6]\n->Array.filterMap(n => mod(n, 2) == 0 ? Some(n * n) : None)\n->assertEqual([4, 16, 36])\n\nArray.filterMap([1, 2, 3, 4, 5, 6], _ => None)->assertEqual([])\n\nArray.filterMap([], n => mod(n, 2) == 0 ? Some(n * n) : None)->assertEqual([])\n```\n"}
67+
}, {
68+
"label": "findLastWithIndex",
69+
"kind": 12,
70+
"tags": [],
71+
"detail": "(array<'a>, ('a, int) => bool) => option<'a>",
72+
"documentation": {"kind": "markdown", "value": "\n`findLastWithIndex(array, checker)` returns the last element of `array` where the provided `checker` function returns true.\n\nSee [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN.\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3]\n\narray\n->Array.findLastWithIndex((item, index) => index < 2 && item > 0)\n->assertEqual(Some(2))\n```\n"}
73+
}, {
74+
"label": "findLast",
75+
"kind": 12,
76+
"tags": [],
77+
"detail": "(array<'a>, 'a => bool) => option<'a>",
78+
"documentation": {"kind": "markdown", "value": "\n`findLast(array, checker)` returns the last element of `array` where the provided `checker` function returns true.\n\nSee [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN.\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3]\n\narray\n->Array.findLast(item => item > 0)\n->assertEqual(Some(3))\n```\n"}
6779
}, {
6880
"label": "shift",
6981
"kind": 12,
@@ -178,6 +190,12 @@ Path Array.
178190
"tags": [],
179191
"detail": "(array<'a>, 'a) => bool",
180192
"documentation": {"kind": "markdown", "value": "\n`includes(array, item)` checks whether `array` includes `item`, by doing a [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality).\n\nSee [`Array.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) on MDN.\n\n## Examples\n\n```rescript\n[1, 2]->Array.includes(1)->assertEqual(true)\n[1, 2]->Array.includes(3)->assertEqual(false)\n\n[{\"language\": \"ReScript\"}]\n->Array.includes({\"language\": \"ReScript\"})\n->assertEqual(false) // false, because of strict equality\n```\n"}
193+
}, {
194+
"label": "findLastIndex",
195+
"kind": 12,
196+
"tags": [],
197+
"detail": "(array<'a>, 'a => bool) => int",
198+
"documentation": {"kind": "markdown", "value": "\n`findLastIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript, ReScript]\n\narray\n->Array.findLastIndex(item => item == ReScript)\n->assertEqual(2)\n\narray->Array.findLastIndex(item => item == TypeScript)\n->assertEqual(-1)\n```\n"}
181199
}, {
182200
"label": "fromInitializer",
183201
"kind": 12,
@@ -298,6 +316,12 @@ Path Array.
298316
"tags": [],
299317
"detail": "array<'a> => unit",
300318
"documentation": {"kind": "markdown", "value": "\n`reverse(array)` reverses the order of the items in `array`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.reverse\n\nsomeArray->assertEqual([\"hello\", \"hi\"])\n```\n"}
319+
}, {
320+
"label": "findLastIndexWithIndex",
321+
"kind": 12,
322+
"tags": [],
323+
"detail": "(array<'a>, ('a, int) => bool) => int",
324+
"documentation": {"kind": "markdown", "value": "\n`findLastIndexWithIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript, JavaScript, ReScript]\n\nlet isReScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == ReScript)\nlet isTypeScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == TypeScript)\n\nassertEqual(isReScriptLast, 3)\nassertEqual(isTypeScriptLast, -1)\n```\n"}
301325
}, {
302326
"label": "getUnsafe",
303327
"kind": 12,
@@ -520,6 +544,12 @@ Path Array.
520544
"tags": [],
521545
"detail": "(array<'a>, int) => unit",
522546
"documentation": {"kind": "markdown", "value": "\n`removeInPlace(array, index)` removes the item at the specified `index` from `array`.\n\nBeware this will *mutate* the array.\n\n## Examples\n\n```rescript\nlet array = []\narray->Array.removeInPlace(0)\nassertEqual(array, []) // Removing from an empty array does nothing\n\nlet array2 = [\"Hello\", \"Hi\", \"Good bye\"]\narray2->Array.removeInPlace(1)\nassertEqual(array2, [\"Hello\", \"Good bye\"]) // Removes the item at index 1\n```\n "}
547+
}, {
548+
"label": "findLastIndexOpt",
549+
"kind": 12,
550+
"tags": [],
551+
"detail": "(array<'a>, 'a => bool) => option<int>",
552+
"documentation": {"kind": "markdown", "value": "\n`findIndexOpt(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.\n\nReturns `None` if no item matches.\n\nSee [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"hello\", \"world\", \"!\"]\n\narray\n->Array.findLastIndexOpt(item => item->String.includes(\"o\"))\n->assertEqual(Some(1))\n```\n"}
523553
}, {
524554
"label": "pushMany",
525555
"kind": 12,

0 commit comments

Comments
 (0)