Skip to content

Commit d020c32

Browse files
Add reverse find functions (#26)
Add new functions related to finding items in arrays in reverse: - `Array.reverseFind` - `Array.reverseFindIndex` - `Array.reverseFindIndexByValue` - `Array.reverseFindMap`
1 parent b667b16 commit d020c32

10 files changed

+250
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Changelog
22

3+
- add `Array.reverseFind`, `Array.reverseFindIndex`, `Array.reverseFindIndexByValue`, and `Array.reverseFindMap` ([#26](https://github.com/seaofvoices/luau-disk/pull/26))
34
- add `Set.intersect` ([#25](https://github.com/seaofvoices/luau-disk/pull/25))
45
- add `Set.toArray` ([#24](https://github.com/seaofvoices/luau-disk/pull/24))
56
- add `Set.removeValues` ([#23](https://github.com/seaofvoices/luau-disk/pull/23))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
local jestGlobals = require('@pkg/@jsdotlua/jest-globals')
2+
3+
local reverseFind = require('../reverseFind')
4+
5+
local expect = jestGlobals.expect
6+
local it = jestGlobals.it
7+
8+
it('finds the last element matching the predicate', function()
9+
local array = { 1, 2, 3, 4, 5 }
10+
local result = reverseFind(array, function(element)
11+
return element % 2 == 0
12+
end)
13+
14+
expect(result).toBe(4)
15+
end)
16+
17+
it('returns nil when no element matches', function()
18+
local array = { 1, 3, 5, 7, 9 }
19+
local result = reverseFind(array, function(element)
20+
return element % 2 == 0
21+
end)
22+
23+
expect(result).toBe(nil)
24+
end)
25+
26+
it('starts from the given index', function()
27+
local array = { 1, 2, 3, 4, 5 }
28+
local result = reverseFind(array, function(element)
29+
return element % 2 == 0
30+
end, 3)
31+
32+
expect(result).toBe(2)
33+
end)
34+
35+
it('handles empty array', function()
36+
local array = {}
37+
local result = reverseFind(array, function(_element)
38+
return true
39+
end)
40+
41+
expect(result).toBe(nil)
42+
end)
43+
44+
return nil
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
local jestGlobals = require('@pkg/@jsdotlua/jest-globals')
2+
3+
local reverseFindIndex = require('../reverseFindIndex')
4+
5+
local expect = jestGlobals.expect
6+
local it = jestGlobals.it
7+
8+
it('finds the index of the last element matching the predicate', function()
9+
local array = { 1, 2, 3, 4, 5 }
10+
local result = reverseFindIndex(array, function(element)
11+
return element % 2 == 0
12+
end)
13+
14+
expect(result).toBe(4)
15+
end)
16+
17+
it('returns nil when no element matches', function()
18+
local array = { 1, 3, 5, 7, 9 }
19+
local result = reverseFindIndex(array, function(element)
20+
return element % 2 == 0
21+
end)
22+
23+
expect(result).toBe(nil)
24+
end)
25+
26+
it('starts from the given index', function()
27+
local array = { 1, 2, 3, 4, 5 }
28+
local result = reverseFindIndex(array, function(element)
29+
return element % 2 == 0
30+
end, 3)
31+
32+
expect(result).toBe(2)
33+
end)
34+
35+
it('handles empty array', function()
36+
local array = {}
37+
local result = reverseFindIndex(array, function(_element)
38+
return true
39+
end)
40+
41+
expect(result).toBe(nil)
42+
end)
43+
44+
return nil
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
local jestGlobals = require('@pkg/@jsdotlua/jest-globals')
2+
3+
local reverseFindIndexByValue = require('../reverseFindIndexByValue')
4+
5+
local expect = jestGlobals.expect
6+
local it = jestGlobals.it
7+
8+
it('finds the index of the last matching value', function()
9+
local array = { 1, 2, 3, 2, 4 }
10+
local result = reverseFindIndexByValue(array, 2)
11+
12+
expect(result).toBe(4)
13+
end)
14+
15+
it('returns nil when value is not found', function()
16+
local array = { 1, 2, 3, 4, 5 }
17+
local result = reverseFindIndexByValue(array, 6)
18+
19+
expect(result).toBe(nil)
20+
end)
21+
22+
it('starts from the given index', function()
23+
local array = { 1, 2, 3, 2, 4 }
24+
local result = reverseFindIndexByValue(array, 2, 3)
25+
26+
expect(result).toBe(2)
27+
end)
28+
29+
it('handles empty array', function()
30+
local array = {}
31+
local result = reverseFindIndexByValue(array, 1)
32+
33+
expect(result).toBe(nil)
34+
end)
35+
36+
return nil
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
local jestGlobals = require('@pkg/@jsdotlua/jest-globals')
2+
3+
local reverseFindMap = require('../reverseFindMap')
4+
5+
local expect = jestGlobals.expect
6+
local it = jestGlobals.it
7+
8+
it('returns the first non-nil mapped value from the end', function()
9+
local array = { 1, 2, 3, 4, 5 }
10+
local result = reverseFindMap(array, function(element)
11+
if element % 2 == 0 then
12+
return element * 2
13+
end
14+
return nil
15+
end)
16+
17+
expect(result).toBe(8)
18+
end)
19+
20+
it('returns nil when no mapped value is non-nil', function()
21+
local array = { 1, 3, 5, 7, 9 }
22+
local result = reverseFindMap(array, function(element)
23+
if element % 2 == 0 then
24+
return element * 2
25+
end
26+
return nil
27+
end)
28+
29+
expect(result).toBe(nil)
30+
end)
31+
32+
it('starts from the given index', function()
33+
local array = { 1, 2, 3, 4, 5 }
34+
local result = reverseFindMap(array, function(element)
35+
if element % 2 == 0 then
36+
return element * 2
37+
end
38+
return nil
39+
end, 3)
40+
41+
expect(result).toBe(4)
42+
end)
43+
44+
it('handles empty array', function()
45+
local array = {}
46+
local result = reverseFindMap(array, function(element)
47+
return element
48+
end)
49+
50+
expect(result).toBe(nil)
51+
end)
52+
53+
return nil

src/array/reverseFind.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
local function reverseFind<T>(
2+
array: { T },
3+
predicate: (element: T, index: number) -> boolean,
4+
start: number?
5+
): T?
6+
local length = #array
7+
8+
for i = start or length, 1, -1 do
9+
local element = array[i]
10+
if predicate(element, i) then
11+
return element
12+
end
13+
end
14+
15+
return nil
16+
end
17+
18+
return reverseFind

src/array/reverseFindIndex.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
local function reverseFindIndex<T>(
2+
array: { T },
3+
predicate: (element: T, index: number) -> boolean,
4+
start: number?
5+
): number?
6+
local length = #array
7+
8+
for i = start or length, 1, -1 do
9+
local element = array[i]
10+
if predicate(element, i) then
11+
return i
12+
end
13+
end
14+
15+
return nil
16+
end
17+
18+
return reverseFindIndex
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
local function reverseFindIndexByValue<T>(array: { T }, element: T, start: number?): number?
2+
local length = #array
3+
4+
for i = start or length, 1, -1 do
5+
if array[i] == element then
6+
return i
7+
end
8+
end
9+
10+
return nil
11+
end
12+
13+
return reverseFindIndexByValue

src/array/reverseFindMap.lua

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
local function reverseFindMap<T, U>(
2+
array: { T },
3+
mapFn: (element: T, index: number) -> U?,
4+
start: number?
5+
): U?
6+
local length = #array
7+
8+
for i = start or length, 1, -1 do
9+
local element = array[i]
10+
local result = mapFn(element, i)
11+
if result ~= nil then
12+
return result
13+
end
14+
end
15+
16+
return nil
17+
end
18+
19+
return reverseFindMap

src/init.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ local Disk = {
4444
removeValues = require('./array/removeValues'),
4545
reverse = require('./array/reverse'),
4646
reversed = require('./array/reverse'),
47+
reverseFind = require('./array/reverseFind'),
48+
reverseFindIndex = require('./array/reverseFindIndex'),
49+
reverseFindIndexByValue = require('./array/reverseFindIndexByValue'),
50+
reverseFindMap = require('./array/reverseFindMap'),
4751
sort = require('./array/sort'),
4852
sortByKey = require('./array/sortByKey'),
4953
stepBy = require('./array/stepBy'),

0 commit comments

Comments
 (0)