diff --git a/imports/array/shared.lua b/imports/array/shared.lua index c8cf9cc..70d0284 100644 --- a/imports/array/shared.lua +++ b/imports/array/shared.lua @@ -1,6 +1,13 @@ ---@class Array : OxClass lib.array = lib.class('Array') +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 + + ---@alias ArrayLike Array | { [number]: T } ---@private @@ -19,10 +26,50 @@ function lib.array:__newindex(index, value) rawset(self, index, value) end +---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 + return lib.array:new(string.strsplit('delimiter', iter)) + 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 + + error('Array.from argument was not a valid iterable value (received %s)') +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 + ---Create a new array containing the elements of two or more arrays. ---@param ... ArrayLike function lib.array:merge(...) - local newArr = table.clone(self) + local newArr = table_clone(self) local length = #self local arrays = { ... } @@ -35,7 +82,7 @@ function lib.array:merge(...) end end - return lib.array:new(table.unpack(newArr)) + return lib.array:new(table_unpack(newArr)) end ---Tests if all elements in an array succeed in passing the provided test function. @@ -50,7 +97,26 @@ function lib.array:every(testFn) return true end ----Creates a new array containing the elements from an array thtat pass the test of the provided function. +---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. ---@param testFn fun(element: unknown): boolean function lib.array:filter(testFn) local newArr = {} @@ -65,7 +131,7 @@ function lib.array:filter(testFn) end end - return lib.array:new(table.unpack(newArr)) + return lib.array:new(table_unpack(newArr)) end ---Returns the first or last element of an array that passes the provided test function. @@ -141,7 +207,7 @@ end ---Concatenates all array elements into a string, seperated by commas or the specified seperator. ---@param seperator? string function lib.array:join(seperator) - return table.concat(self, seperator or ',') + return table_concat(self, seperator or ',') end ---Create a new array containing the results from calling the provided function on every element in an array. @@ -153,12 +219,12 @@ function lib.array:map(cb) arr[i] = cb(self[i], i, self) end - return lib.array:new(table.unpack(arr)) + return lib.array:new(table_unpack(arr)) end ---Removes the last element from an array and returns the removed element. function lib.array:pop() - return table.remove(self) + return table_remove(self) end ---Adds the given elements to the end of an array and returns the new array length. @@ -175,18 +241,27 @@ function lib.array:push(...) return length end ----The "reducer" function is applied to every element within an array, with the previous element's result serving as the accumulator.\ +---The "reducer" function is applied to every element within an array, with the previous element's result serving as the accumulator. ---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 +---@param reverse? boolean Iterate over the array from right-to-left. ---@return T -function lib.array:reduce(reducer, initialValue) +function lib.array:reduce(reducer, initialValue, reverse) + local length = #self local initialIndex = initialValue and 1 or 2 local accumulator = initialValue or self[1] - for i = initialIndex, #self do - accumulator = reducer(accumulator, self[i], i) + 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 end return accumulator @@ -207,7 +282,31 @@ end ---Removes the first element from an array and returns the removed element. function lib.array:shift() - return table.remove(self, 1) + 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 end ---Creates a new array with reversed elements from the given array. @@ -221,11 +320,29 @@ function lib.array:toReversed() return reversed end +---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 + ---Returns true if the given table is an instance of array or an array-like table. ---@param tbl ArrayLike ---@return boolean function lib.array.isArray(tbl) - local tableType = table.type(tbl) + local tableType = table_type(tbl) if not tableType then return false end