diff --git a/CHANGELOG.md b/CHANGELOG.md index 96d70a5b..dd29569d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### API changes - Add `Result.forEach` https://github.com/rescript-association/rescript-core/pull/116 +- Add missing Array functions : `indexOfFromOpt`, `findLast`, `findLastIndex`, `findLastIndexOpt`, `findLastIndexWithIndex`, `findLastIndexWithIndexOpt` https://github.com/rescript-association/rescript-core/pull/126/files ## 0.2.0 diff --git a/src/Core__Array.mjs b/src/Core__Array.mjs index 1560df8f..87fef9dd 100644 --- a/src/Core__Array.mjs +++ b/src/Core__Array.mjs @@ -138,11 +138,36 @@ function findMap(arr, f) { }; } +function findLastIndexOpt(xs, pred) { + var inx = xs.findLastIndex(pred); + if (inx !== -1) { + return inx; + } + +} + +function findLastIndexWithIndexOpt(xs, pred) { + var inx = xs.findLastIndex(pred); + if (inx !== -1) { + return inx; + } + +} + +function indexOfFromOpt(xs, val, fromInx) { + var inx = xs.indexOf(val, fromInx); + if (inx !== -1) { + return inx; + } + +} + export { make , fromInitializer , sort , indexOfOpt , + indexOfFromOpt , lastIndexOfOpt , reduce , reduceWithIndex , @@ -155,5 +180,7 @@ export { shuffle , shuffleInPlace , findMap , + findLastIndexOpt , + findLastIndexWithIndexOpt , } /* No side effect */ diff --git a/src/Core__Array.res b/src/Core__Array.res index cd1bda48..82d0cd0e 100644 --- a/src/Core__Array.res +++ b/src/Core__Array.res @@ -214,3 +214,30 @@ let findMap = (arr, f) => { } @send external at: (array<'a>, int) => option<'a> = "at" + +@send +external findLast: (array<'a>, 'a => bool) => option<'a> = "findLast" + +@send +external findLastIndex: (array<'a>, 'a => bool) => int = "findLastIndex" + +let findLastIndexOpt = (xs, pred) => + switch findLastIndex(xs, pred) { + | -1 => None + | inx => Some(inx) + } + +@send +external findLastIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findLastIndex" + +let findLastIndexWithIndexOpt = (xs, pred) => + switch findLastIndexWithIndex(xs, pred) { + | -1 => None + | inx => Some(inx) + } + +let indexOfFromOpt = (xs, val, fromInx) => + switch indexOfFrom(xs, val, fromInx) { + | -1 => None + | inx => Some(inx) + } diff --git a/src/Core__Array.resi b/src/Core__Array.resi index 253f0cf2..39364a51 100644 --- a/src/Core__Array.resi +++ b/src/Core__Array.resi @@ -369,8 +369,11 @@ Console.log([{"language": "ReScript"}]->Array.indexOfOpt({"language": "ReScript" ``` */ let indexOfOpt: (array<'a>, 'a) => option + @send external indexOfFrom: (array<'a>, 'a, int) => int = "indexOf" +let indexOfFromOpt: (array<'a>, 'a, int) => option + /** `joinWith(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items. @@ -383,9 +386,53 @@ Console.log(array->Array.joinWith(" -- ")) // 1 -- 2 -- 3 */ @send external joinWith: (array<'a>, string) => string = "join" -@send external lastIndexOf: (array<'a>, 'a) => int = "lastIndexOf" + +/** +`lastIndexOf(array, item)` returns the last index of `item` in `array`, or `-1` if it is not present. **Note:** [Strict equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) is used when searching, which may produce unexpected results; use `Array.findLastIndexOf` to search by value. + +See [Array.lastIndexOf on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf). + +## Examples +```rescript +[3, 5, 7, 5, 8]->Array.lastIndexOf(5) // 3 +[3, 5, 7, 5, 8]->Array.lastIndexOf(99) // -1 +[{"color": "red"}]->Array.lastIndexOf({"color": "red"}) // -1, because of strict equality +``` +*/ +@send +external lastIndexOf: (array<'a>, 'a) => int = "lastIndexOf" + +/** +`lastIndexOfOpt(array, item)` returns the last index of `item` in `array`, or `None` if it is not present. **Note:** [Strict equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) is used when searching, which may produce unexpected results; use `Array.findLastIndexOf` to search by value. + +See [Array.lastIndexOf on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf). + +## Examples +```rescript +[3, 5, 7, 5, 8]->Array.lastIndexOf(5) // Some(3) +[3, 5, 7, 5, 8]->Array.lastIndexOf(99) // None +[{"color": "red"}]->Array.lastIndexOf({"color": "red"}) // None, because of strict equality +``` +*/ let lastIndexOfOpt: (array<'a>, 'a) => option -@send external lastIndexOfFrom: (array<'a>, 'a, int) => int = "lastIndexOf" + +/** +`lastIndexOfFrom(array, item, fromIndex)` returns the last index of `item` in `array`, or `-1` if it is not present. The search begins at `fromIndex`. A negative index counts back from the end of the array. + +**Note:** [Strict equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) is used when searching, which may produce unexpected results; use `Array.findLastIndexOf` to search by value. + +See [Array.lastIndexOf on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf). + +## Examples +```rescript +[3, 5, 7, 5, 8]->Array.lastIndexOfFrom(5, -3) // 1 +[3, 5, 7, 5, 8]->Array.lastIndexOfFrom(5, 4) // 3 +[3, 5, 7, 5, 8]->Array.lastIndexOfFrom(5, 0) // -1 +[{"color": "red"}]->Array.lastIndexOfFrom({"color": "red"}, 99) // -1, because of strict equality +``` +*/ +@send +external lastIndexOfFrom: (array<'a>, 'a, int) => int = "lastIndexOf" /** `slice(array, ~start, ~end)` creates a new array of items copied from `array` from `start` until (but not including) `end`. @@ -955,3 +1002,81 @@ let findMap: (array<'a>, 'a => option<'b>) => option<'b> */ @send external at: (array<'a>, int) => option<'a> = "at" + +/** +`findLast(array, predicate)` iterates the array in **reverse** order and returns the value of the first element that satisfies the provided testing function. Returns `None` if no elements satisfy the predicate. + +See [Array.findLast on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) + +## Examples +```rescript +let nums = [3, 5, 7, 5, 8] +nums->Array.findLast(i => i < 7) // Some(5) +nums->Array.findLast(i=> i > 100) // None +[]->Array.findLast(_ => true) // None +``` +*/ +@send +external findLast: (array<'a>, 'a => bool) => option<'a> = "findLast" + +/** +`findLastIndex(array, predicate)` iterates the array in **reverse** order and returns the index of the first element that satisfies the provided testing function. Returns `-1` if no elements satisfy the predicate. + +See [Array.findLastIndex on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) + +## Examples +```rescript +let nums = [3, 5, 7, 5, 8] +nums->Array.findLastIndex(i => i < 7) // 3 +nums->Array.findLast(i => i > 100) // -1 +[]->Array.findLast(_ => true) // -1 +``` +*/ +@send +external findLastIndex: (array<'a>, 'a => bool) => int = "findLastIndex" + +/** +`findLastIndexOpt(array, predicate)` iterates the array in **reverse** order and returns the index of the first element that satisfies the provided testing function. Returns `None` if no elements satisfy the predicate. + +See [Array.findLastIndex on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) + +## Examples +```rescript +let nums = [3, 5, 7, 5, 8] +nums->Array.findLastIndex(i => i < 7) // Some(3) +nums->Array.findLast(i => i > 100) // None +[]->Array.findLast(_ => true) // None +``` +*/ +let findLastIndexOpt: (array<'a>, 'a => bool) => option + +/** +`findLastIndexWithIndex(array, predicate)` iterates the array in **reverse** order and returns the index of the first element that satisfies the callback `predicate`. The callback receives the current element being processed followed by its index. Returns `-1` if no elements satisfy the predicate. + +See [Array.findLastIndex on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) + +## Examples +```rescript +let nums = [3, 5, 7, 5, 8] +nums->Array.findLastIndexWithIndex((val, inx) => val == 5 && inx <= 2) // 1 +nums->Array.findLastIndexWithIndex((val, inx) => val == 5 && inx >= 1) // 3 +nums->Array.findLastIndexWithIndex((val, inx) => val >= 8 && inx < 2) // -1 +``` +*/ +@send +external findLastIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findLastIndex" + +/** +`findLastIndexWithIndexOpt(array, predicate)` iterates the array in **reverse** order and returns the index of the first element that satisfies the callback `predicate`. The callback receives the current element being processed followed by its index. Returns `None` if no elements satisfy the predicate. + +See [Array.findLastIndex on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) + +## Examples +```rescript +let nums = [3, 5, 7, 5, 8] +nums->Array.findLastIndexWithIndex((val, inx) => val == 5 && inx <= 2) // 1 +nums->Array.findLastIndexWithIndex((val, inx) => val == 5 && inx >= 1) // 3 +nums->Array.findLastIndexWithIndex((val, inx) => val >= 8 && inx < 2) // None +``` +*/ +let findLastIndexWithIndexOpt: (array<'a>, ('a, int) => bool) => option diff --git a/test/ArrayTests.mjs b/test/ArrayTests.mjs index 7cc4a4c6..9cf2b75c 100644 --- a/test/ArrayTests.mjs +++ b/test/ArrayTests.mjs @@ -401,6 +401,376 @@ Test.run([ })), eq, undefined); +Test.run([ + [ + "ArrayTests.res", + 102, + 20, + 33 + ], + "lastIndexOf" + ], [ + 3, + 5, + 7, + 5, + 8 + ].lastIndexOf(5), eq, 3); + +Test.run([ + [ + "ArrayTests.res", + 103, + 20, + 33 + ], + "lastIndexOf" + ], [ + 3, + 5, + 7, + 5, + 8 + ].lastIndexOf(100), eq, -1); + +Test.run([ + [ + "ArrayTests.res", + 104, + 20, + 33 + ], + "lastIndexOf" + ], [].lastIndexOf(100), eq, -1); + +Test.run([ + [ + "ArrayTests.res", + 105, + 20, + 33 + ], + "lastIndexOf" + ], [{ + a: 1 + }].lastIndexOf({ + a: 1 + }), eq, -1); + +Test.run([ + [ + "ArrayTests.res", + 107, + 20, + 36 + ], + "lastIndexOfOpt" + ], Core__Array.lastIndexOfOpt([ + 3, + 5, + 7, + 5, + 8 + ], 5), eq, 3); + +Test.run([ + [ + "ArrayTests.res", + 108, + 20, + 36 + ], + "lastIndexOfOpt" + ], Core__Array.lastIndexOfOpt([ + 3, + 5, + 7, + 5, + 8 + ], 100), eq, undefined); + +Test.run([ + [ + "ArrayTests.res", + 109, + 20, + 36 + ], + "lastIndexOfOpt" + ], Core__Array.lastIndexOfOpt([], 100), eq, undefined); + +Test.run([ + [ + "ArrayTests.res", + 110, + 20, + 36 + ], + "lastIndexOfOpt" + ], Core__Array.lastIndexOfOpt([{ + a: 1 + }], { + a: 1 + }), eq, undefined); + +Test.run([ + [ + "ArrayTests.res", + 112, + 20, + 37 + ], + "lastIndexOfFrom" + ], [ + 3, + 5, + 7, + 5, + 8 + ].lastIndexOf(5, -3), eq, 1); + +Test.run([ + [ + "ArrayTests.res", + 113, + 20, + 37 + ], + "lastIndexOfFrom" + ], [ + 3, + 5, + 7, + 5, + 8 + ].lastIndexOf(5, 4), eq, 3); + +Test.run([ + [ + "ArrayTests.res", + 114, + 20, + 37 + ], + "lastIndexOfFrom" + ], [ + 3, + 5, + 7, + 5, + 8 + ].lastIndexOf(5, 0), eq, -1); + +Test.run([ + [ + "ArrayTests.res", + 116, + 20, + 30 + ], + "findLast" + ], [ + 3, + 5, + 7, + 5, + 8 + ].findLast(function (i) { + return i < 8; + }), eq, 5); + +Test.run([ + [ + "ArrayTests.res", + 117, + 20, + 30 + ], + "findLast" + ], [].findLast(function (param) { + return true; + }), eq, undefined); + +Test.run([ + [ + "ArrayTests.res", + 118, + 20, + 30 + ], + "findLast" + ], [ + 3, + 5, + 7, + 5, + 8 + ].findLast(function (i) { + return i > 100; + }), eq, undefined); + +Test.run([ + [ + "ArrayTests.res", + 120, + 20, + 35 + ], + "findLastIndex" + ], [ + 3, + 5, + 7, + 5, + 8 + ].findLastIndex(function (i) { + return i === 5; + }), eq, 3); + +Test.run([ + [ + "ArrayTests.res", + 121, + 20, + 35 + ], + "findLastIndex" + ], [ + 3, + 5, + 7, + 5, + 8 + ].findLastIndex(function (i) { + return i > 100; + }), eq, -1); + +Test.run([ + [ + "ArrayTests.res", + 122, + 20, + 35 + ], + "findLastIndex" + ], [].findLastIndex(function (param) { + return true; + }), eq, -1); + +Test.run([ + [ + "ArrayTests.res", + 125, + 13, + 31 + ], + "findLastIndexOpt" + ], Core__Array.findLastIndexOpt([ + 3, + 5, + 7, + 5, + 8 + ], (function (i) { + return i === 5; + })), eq, 3); + +Test.run([ + [ + "ArrayTests.res", + 131, + 13, + 31 + ], + "findLastIndexOpt" + ], Core__Array.findLastIndexOpt([ + 3, + 5, + 7, + 5, + 8 + ], (function (i) { + return i > 100; + })), eq, undefined); + +Test.run([ + [ + "ArrayTests.res", + 136, + 20, + 38 + ], + "findLastIndexOpt" + ], Core__Array.findLastIndexOpt([], (function (param) { + return true; + })), eq, undefined); + +Test.run([ + [ + "ArrayTests.res", + 139, + 13, + 37 + ], + "findLastIndexWithIndex" + ], [ + 3, + 5, + 7, + 5, + 8 + ].findLastIndex(function (val, inx) { + if (val === 5) { + return inx <= 2; + } else { + return false; + } + }), eq, 1); + +Test.run([ + [ + "ArrayTests.res", + 145, + 13, + 37 + ], + "findLastIndexWithIndex" + ], [ + 3, + 5, + 7, + 5, + 8 + ].findLastIndex(function (val, inx) { + if (val === 5) { + return inx >= 1; + } else { + return false; + } + }), eq, 3); + +Test.run([ + [ + "ArrayTests.res", + 151, + 13, + 37 + ], + "findLastIndexWithIndex" + ], [ + 3, + 5, + 7, + 5, + 8 + ].findLastIndex(function (val, inx) { + if (val >= 8) { + return inx < 2; + } else { + return false; + } + }), eq, -1); + export { eq , } diff --git a/test/ArrayTests.res b/test/ArrayTests.res index 40c352f7..5884f1e9 100644 --- a/test/ArrayTests.res +++ b/test/ArrayTests.res @@ -98,3 +98,58 @@ Test.run( eq, None, ) + +Test.run(__POS_OF__("lastIndexOf"), [3, 5, 7, 5, 8]->Array.lastIndexOf(5), eq, 3) +Test.run(__POS_OF__("lastIndexOf"), [3, 5, 7, 5, 8]->Array.lastIndexOf(100), eq, -1) +Test.run(__POS_OF__("lastIndexOf"), []->Array.lastIndexOf(100), eq, -1) +Test.run(__POS_OF__("lastIndexOf"), [{"a": 1}]->Array.lastIndexOf({"a": 1}), eq, -1) + +Test.run(__POS_OF__("lastIndexOfOpt"), [3, 5, 7, 5, 8]->Array.lastIndexOfOpt(5), eq, Some(3)) +Test.run(__POS_OF__("lastIndexOfOpt"), [3, 5, 7, 5, 8]->Array.lastIndexOfOpt(100), eq, None) +Test.run(__POS_OF__("lastIndexOfOpt"), []->Array.lastIndexOfOpt(100), eq, None) +Test.run(__POS_OF__("lastIndexOfOpt"), [{"a": 1}]->Array.lastIndexOfOpt({"a": 1}), eq, None) + +Test.run(__POS_OF__("lastIndexOfFrom"), [3, 5, 7, 5, 8]->Array.lastIndexOfFrom(5, -3), eq, 1) +Test.run(__POS_OF__("lastIndexOfFrom"), [3, 5, 7, 5, 8]->Array.lastIndexOfFrom(5, 4), eq, 3) +Test.run(__POS_OF__("lastIndexOfFrom"), [3, 5, 7, 5, 8]->Array.lastIndexOfFrom(5, 0), eq, -1) + +Test.run(__POS_OF__("findLast"), [3, 5, 7, 5, 8]->Array.findLast(i => i < 8), eq, Some(5)) +Test.run(__POS_OF__("findLast"), []->Array.findLast(_ => true), eq, None) +Test.run(__POS_OF__("findLast"), [3, 5, 7, 5, 8]->Array.findLast(i => i > 100), eq, None) + +Test.run(__POS_OF__("findLastIndex"), [3, 5, 7, 5, 8]->Array.findLastIndex(i => i == 5), eq, 3) +Test.run(__POS_OF__("findLastIndex"), [3, 5, 7, 5, 8]->Array.findLastIndex(i => i > 100), eq, -1) +Test.run(__POS_OF__("findLastIndex"), []->Array.findLastIndex(_ => true), eq, -1) + +Test.run( + __POS_OF__("findLastIndexOpt"), + [3, 5, 7, 5, 8]->Array.findLastIndexOpt(i => i == 5), + eq, + Some(3), +) +Test.run( + __POS_OF__("findLastIndexOpt"), + [3, 5, 7, 5, 8]->Array.findLastIndexOpt(i => i > 100), + eq, + None, +) +Test.run(__POS_OF__("findLastIndexOpt"), []->Array.findLastIndexOpt(_ => true), eq, None) + +Test.run( + __POS_OF__("findLastIndexWithIndex"), + [3, 5, 7, 5, 8]->Array.findLastIndexWithIndex((val, inx) => val == 5 && inx <= 2), + eq, + 1, +) +Test.run( + __POS_OF__("findLastIndexWithIndex"), + [3, 5, 7, 5, 8]->Array.findLastIndexWithIndex((val, inx) => val == 5 && inx >= 1), + eq, + 3, +) +Test.run( + __POS_OF__("findLastIndexWithIndex"), + [3, 5, 7, 5, 8]->Array.findLastIndexWithIndex((val, inx) => val >= 8 && inx < 2), + eq, + -1, +)