2024-04-13 11:15:26 +10:00
---@class Array : OxClass
2024-07-26 15:21:09 +10:00
lib.array = lib.class ( ' Array ' )
2024-04-13 11:15:26 +10:00
2025-01-29 06:54:06 +11:00
local table_unpack = table.unpack
local table_remove = table.remove
local table_clone = table.clone
local table_concat = table.concat
local table_type = table.type
2024-04-19 03:09:39 +10:00
---@alias ArrayLike<T> Array | { [number]: T }
2024-04-16 14:15:25 +10:00
---@private
2024-07-26 15:21:09 +10:00
function lib . array : constructor ( ... )
2024-04-13 11:15:26 +10:00
local arr = { ... }
for i = 1 , # arr do
self [ i ] = arr [ i ]
end
end
2024-04-16 14:15:25 +10:00
---@private
2024-07-26 15:21:09 +10:00
function lib . array : __newindex ( index , value )
2024-04-13 11:15:26 +10:00
if type ( index ) ~= ' number ' then error ( ( " Cannot insert non-number index '%s' into an array. " ) : format ( index ) ) end
rawset ( self , index , value )
end
2025-01-29 06:54:06 +11:00
---Creates a new array from an iteratable value.
---@param iter table | function | string
---@return Array
function lib . array : from ( iter )
local iterType = type ( iter )
if iterType == ' table ' then
return lib.array : new ( table_unpack ( iter ) )
end
if iterType == ' string ' then
2025-01-29 08:02:06 +11:00
return lib.array : new ( string.strsplit ( ' ' , iter ) )
2025-01-29 06:54:06 +11:00
end
if iterType == ' function ' then
local arr = lib.array : new ( )
local length = 0
for value in iter do
length += 1
arr [ length ] = value
end
return arr
end
2025-01-29 07:13:16 +11:00
error ( ( ' Array.from argument was not a valid iterable value (received %s) ' ) : format ( iterType ) )
2025-01-29 06:54:06 +11:00
end
---Returns the element at the given index, with negative numbers counting backwards from the end of the array.
---@param index number
---@return unknown
function lib . array : at ( index )
if index < 0 then
index = # self + index + 1
end
return self [ index ]
end
2024-10-01 17:39:54 +10:00
---Create a new array containing the elements of two or more arrays.
---@param ... ArrayLike
function lib . array : merge ( ... )
2025-01-29 06:54:06 +11:00
local newArr = table_clone ( self )
2024-04-13 11:15:26 +10:00
local length = # self
2024-10-01 17:39:54 +10:00
local arrays = { ... }
2024-04-13 11:15:26 +10:00
2024-10-01 17:39:54 +10:00
for i = 1 , # arrays do
local arr = arrays [ i ]
for j = 1 , # arr do
length += 1
newArr [ length ] = arr [ j ]
end
2024-04-13 11:15:26 +10:00
end
2025-01-29 06:54:06 +11:00
return lib.array : new ( table_unpack ( newArr ) )
2024-04-13 11:15:26 +10:00
end
---Tests if all elements in an array succeed in passing the provided test function.
---@param testFn fun(element: unknown): boolean
2024-07-26 15:21:09 +10:00
function lib . array : every ( testFn )
2024-04-13 11:15:26 +10:00
for i = 1 , # self do
if not testFn ( self [ i ] ) then
return false
end
end
return true
end
2025-01-29 06:54:06 +11:00
---Sets all elements within a range to the given value and returns the modified array.
---@param value any
---@param start? number
---@param endIndex? number
function lib . array : fill ( value , start , endIndex )
local length = # self
start = start or 1
endIndex = endIndex or length
if start < 1 then start = 1 end
if endIndex > length then endIndex = length end
for i = start , endIndex do
self [ i ] = value
end
return self
end
---Creates a new array containing the elements from an array that pass the test of the provided function.
2024-04-13 11:15:26 +10:00
---@param testFn fun(element: unknown): boolean
2024-07-26 15:21:09 +10:00
function lib . array : filter ( testFn )
2024-04-13 11:15:26 +10:00
local newArr = { }
local length = 0
for i = 1 , # self do
local element = self [ i ]
if testFn ( element ) then
length += 1
newArr [ length ] = element
end
end
2025-01-29 06:54:06 +11:00
return lib.array : new ( table_unpack ( newArr ) )
2024-04-13 11:15:26 +10:00
end
---Returns the first or last element of an array that passes the provided test function.
---@param testFn fun(element: unknown): boolean
---@param last? boolean
2024-07-26 15:21:09 +10:00
function lib . array : find ( testFn , last )
2024-04-13 11:15:26 +10:00
local a = last and # self or 1
local b = last and 1 or # self
local c = last and - 1 or 1
for i = a , b , c do
local element = self [ i ]
if testFn ( element ) then
return element
end
end
end
---Returns the first or last index of the first element of an array that passes the provided test function.
---@param testFn fun(element: unknown): boolean
---@param last? boolean
2024-07-26 15:21:09 +10:00
function lib . array : findIndex ( testFn , last )
2024-04-13 11:15:26 +10:00
local a = last and # self or 1
local b = last and 1 or # self
local c = last and - 1 or 1
for i = a , b , c do
local element = self [ i ]
if testFn ( element ) then
2024-05-02 08:07:25 +02:00
return i
2024-04-13 11:15:26 +10:00
end
end
end
---Returns the first or last index of the first element of an array that matches the provided value.
---@param value unknown
---@param last? boolean
2024-07-26 15:21:09 +10:00
function lib . array : indexOf ( value , last )
2024-04-13 11:15:26 +10:00
local a = last and # self or 1
local b = last and 1 or # self
local c = last and - 1 or 1
for i = a , b , c do
local element = self [ i ]
if element == value then
2025-01-21 11:33:15 +11:00
return i
2024-04-13 11:15:26 +10:00
end
end
end
---Executes the provided function for each element in an array.
---@param cb fun(element: unknown)
2024-07-26 15:21:09 +10:00
function lib . array : forEach ( cb )
2024-04-13 11:15:26 +10:00
for i = 1 , # self do
cb ( self [ i ] )
end
end
2024-10-01 17:39:54 +10:00
---Determines if a given element exists inside an array.
---@param element unknown The value to find in the array.
---@param fromIndex? number The position in the array to begin searching from.
function lib . array : includes ( element , fromIndex )
for i = ( fromIndex or 1 ) , # self do
if self [ i ] == element then return true end
end
return false
end
2024-04-13 11:15:26 +10:00
---Concatenates all array elements into a string, seperated by commas or the specified seperator.
---@param seperator? string
2024-07-26 15:21:09 +10:00
function lib . array : join ( seperator )
2025-01-29 06:54:06 +11:00
return table_concat ( self , seperator or ' , ' )
2024-04-13 11:15:26 +10:00
end
2024-10-01 17:39:54 +10:00
---Create a new array containing the results from calling the provided function on every element in an array.
---@param cb fun(element: unknown, index: number, array: self): unknown
function lib . array : map ( cb )
local arr = { }
for i = 1 , # self do
arr [ i ] = cb ( self [ i ] , i , self )
end
2025-01-29 06:54:06 +11:00
return lib.array : new ( table_unpack ( arr ) )
2024-10-01 17:39:54 +10:00
end
2024-04-13 11:15:26 +10:00
---Removes the last element from an array and returns the removed element.
2024-07-26 15:21:09 +10:00
function lib . array : pop ( )
2025-01-29 06:54:06 +11:00
return table_remove ( self )
2024-04-13 11:15:26 +10:00
end
---Adds the given elements to the end of an array and returns the new array length.
---@param ... any
2024-07-26 15:21:09 +10:00
function lib . array : push ( ... )
2024-04-13 11:15:26 +10:00
local elements = { ... }
local length = # self
for i = 1 , # elements do
length += 1
self [ length ] = elements [ i ]
end
return length
end
2025-01-29 06:54:06 +11:00
---The "reducer" function is applied to every element within an array, with the previous element's result serving as the accumulator.
2024-04-16 14:15:25 +10:00
---If an initial value is provided, it's used as the accumulator for index 1; otherwise, index 1 itself serves as the initial value, and iteration begins from index 2.
---@generic T
---@param reducer fun(accumulator: T, currentValue: T, index?: number): T
---@param initialValue? T
2025-01-29 06:54:06 +11:00
---@param reverse? boolean Iterate over the array from right-to-left.
2024-04-16 14:15:25 +10:00
---@return T
2025-01-29 06:54:06 +11:00
function lib . array : reduce ( reducer , initialValue , reverse )
local length = # self
2024-04-16 14:15:25 +10:00
local initialIndex = initialValue and 1 or 2
local accumulator = initialValue or self [ 1 ]
2025-01-29 06:54:06 +11:00
if reverse then
for i = initialIndex , length do
local index = length - i + initialIndex
accumulator = reducer ( accumulator , self [ index ] , index )
end
else
for i = initialIndex , length do
accumulator = reducer ( accumulator , self [ i ] , i )
end
2024-04-16 14:15:25 +10:00
end
return accumulator
end
2024-10-01 17:39:54 +10:00
---Reverses the elements inside an array.
function lib . array : reverse ( )
local i , j = 1 , # self
while i < j do
self [ i ] , self [ j ] = self [ j ] , self [ i ]
i += 1
j -= 1
end
return self
end
---Removes the first element from an array and returns the removed element.
function lib . array : shift ( )
2025-01-29 06:54:06 +11:00
return table_remove ( self , 1 )
end
---Creates a shallow copy of a portion of an array as a new array.
---@param start? number
---@param finish? number
function lib . array : slice ( start , finish )
local length = # self
start = start or 1
finish = finish or length
if start < 0 then start = length + start + 1 end
if finish < 0 then finish = length + finish + 1 end
if start < 1 then start = 1 end
if finish > length then finish = length end
local arr = lib.array : new ( )
local index = 0
for i = start , finish do
index += 1
arr [ index ] = self [ i ]
end
return arr
2024-10-01 17:39:54 +10:00
end
---Creates a new array with reversed elements from the given array.
function lib . array : toReversed ( )
local reversed = lib.array : new ( )
for i = # self , 1 , - 1 do
reversed : push ( self [ i ] )
end
return reversed
end
2025-01-29 06:54:06 +11:00
---Inserts the given elements to the start of an array and returns the new array length.
---@param ... any
function lib . array : unshift ( ... )
local elements = { ... }
local length = # self
local eLength = # elements
for i = length , 1 , - 1 do
self [ i + eLength ] = self [ i ]
end
for i = 1 , # elements do
self [ i ] = elements [ i ]
end
return length + eLength
end
2024-04-19 03:09:39 +10:00
---Returns true if the given table is an instance of array or an array-like table.
---@param tbl ArrayLike
---@return boolean
2024-07-26 15:21:09 +10:00
function lib . array . isArray ( tbl )
2025-01-29 06:54:06 +11:00
local tableType = table_type ( tbl )
2024-04-19 03:09:39 +10:00
2024-10-01 17:39:54 +10:00
if not tableType then return false end
2024-07-26 15:21:09 +10:00
if tableType == ' array ' or tableType == ' empty ' or lib.array . instanceOf ( tbl , lib.array ) then
2024-04-19 03:09:39 +10:00
return true
end
return false
end
2024-04-13 11:15:26 +10:00
return lib.array