fix table module

This commit is contained in:
Sky Johnson 2025-07-25 09:43:57 -05:00
parent e05369431c
commit 52fe63df39
3 changed files with 229 additions and 3 deletions

View File

@ -3,6 +3,7 @@ local orig_remove = table.remove
local orig_concat = table.concat local orig_concat = table.concat
local orig_sort = table.sort local orig_sort = table.sort
-- Enhanced table.insert with validation
function table.insert(t, pos, value) function table.insert(t, pos, value)
if type(t) ~= "table" then error("table.insert: first argument must be a table", 2) end if type(t) ~= "table" then error("table.insert: first argument must be a table", 2) end
@ -18,6 +19,7 @@ function table.insert(t, pos, value)
end end
end end
-- Enhanced table.remove with validation
function table.remove(t, pos) function table.remove(t, pos)
if type(t) ~= "table" then error("table.remove: first argument must be a table", 2) end if type(t) ~= "table" then error("table.remove: first argument must be a table", 2) end
if pos ~= nil and (type(pos) ~= "number" or pos ~= math.floor(pos)) then if pos ~= nil and (type(pos) ~= "number" or pos ~= math.floor(pos)) then
@ -26,6 +28,7 @@ function table.remove(t, pos)
return orig_remove(t, pos) return orig_remove(t, pos)
end end
-- Enhanced table.concat with validation
function table.concat(t, sep, start_idx, end_idx) function table.concat(t, sep, start_idx, end_idx)
if type(t) ~= "table" then error("table.concat: first argument must be a table", 2) end if type(t) ~= "table" then error("table.concat: first argument must be a table", 2) end
if sep ~= nil and type(sep) ~= "string" then error("table.concat: separator must be a string", 2) end if sep ~= nil and type(sep) ~= "string" then error("table.concat: separator must be a string", 2) end
@ -38,17 +41,24 @@ function table.concat(t, sep, start_idx, end_idx)
return orig_concat(t, sep, start_idx, end_idx) return orig_concat(t, sep, start_idx, end_idx)
end end
-- Enhanced table.sort with validation
function table.sort(t, comp) function table.sort(t, comp)
if type(t) ~= "table" then error("table.sort: first argument must be a table", 2) end if type(t) ~= "table" then error("table.sort: first argument must be a table", 2) end
if comp ~= nil and type(comp) ~= "function" then error("table.sort: comparator must be a function", 2) end if comp ~= nil and type(comp) ~= "function" then error("table.sort: comparator must be a function", 2) end
orig_sort(t, comp) orig_sort(t, comp)
end end
--- Returns the length of an array-like table
-- @param t table to measure
-- @return number of array elements
function table.length(t) function table.length(t)
if type(t) ~= "table" then error("table.length: argument must be a table", 2) end if type(t) ~= "table" then error("table.length: argument must be a table", 2) end
return #t return #t
end end
--- Returns the total number of key-value pairs in a table
-- @param t table to count
-- @return total number of elements
function table.size(t) function table.size(t)
if type(t) ~= "table" then error("table.size: argument must be a table", 2) end if type(t) ~= "table" then error("table.size: argument must be a table", 2) end
local count = 0 local count = 0
@ -58,11 +68,17 @@ function table.size(t)
return count return count
end end
--- Checks if a table is empty
-- @param t table to check
-- @return true if table has no elements
function table.is_empty(t) function table.is_empty(t)
if type(t) ~= "table" then error("table.is_empty: argument must be a table", 2) end if type(t) ~= "table" then error("table.is_empty: argument must be a table", 2) end
return next(t) == nil return next(t) == nil
end end
--- Checks if a table is an array (contiguous integer keys starting from 1)
-- @param t table to check
-- @return true if table is an array
function table.is_array(t) function table.is_array(t)
if type(t) ~= "table" then error("table.is_array: argument must be a table", 2) end if type(t) ~= "table" then error("table.is_array: argument must be a table", 2) end
if table.is_empty(t) then return true end if table.is_empty(t) then return true end
@ -79,6 +95,8 @@ function table.is_array(t)
return max_index == count return max_index == count
end end
--- Removes all elements from a table
-- @param t table to clear
function table.clear(t) function table.clear(t)
if type(t) ~= "table" then error("table.clear: argument must be a table", 2) end if type(t) ~= "table" then error("table.clear: argument must be a table", 2) end
for k in pairs(t) do for k in pairs(t) do
@ -86,6 +104,9 @@ function table.clear(t)
end end
end end
--- Creates a shallow copy of a table
-- @param t table to clone
-- @return new table with same key-value pairs
function table.clone(t) function table.clone(t)
if type(t) ~= "table" then error("table.clone: argument must be a table", 2) end if type(t) ~= "table" then error("table.clone: argument must be a table", 2) end
local result = {} local result = {}
@ -95,6 +116,9 @@ function table.clone(t)
return result return result
end end
--- Creates a deep copy of a table, handling circular references
-- @param t table to deep copy
-- @return new table with recursively copied values
function table.deep_copy(t) function table.deep_copy(t)
if type(t) ~= "table" then error("table.deep_copy: argument must be a table", 2) end if type(t) ~= "table" then error("table.deep_copy: argument must be a table", 2) end
@ -115,6 +139,10 @@ function table.deep_copy(t)
return copy_recursive(t, {}) return copy_recursive(t, {})
end end
--- Checks if a table contains a specific value
-- @param t table to search
-- @param value value to find
-- @return true if value is found
function table.contains(t, value) function table.contains(t, value)
if type(t) ~= "table" then error("table.contains: first argument must be a table", 2) end if type(t) ~= "table" then error("table.contains: first argument must be a table", 2) end
for _, v in pairs(t) do for _, v in pairs(t) do
@ -123,6 +151,10 @@ function table.contains(t, value)
return false return false
end end
--- Returns the first key that maps to the given value
-- @param t table to search
-- @param value value to find
-- @return key that maps to value, or nil if not found
function table.index_of(t, value) function table.index_of(t, value)
if type(t) ~= "table" then error("table.index_of: first argument must be a table", 2) end if type(t) ~= "table" then error("table.index_of: first argument must be a table", 2) end
for k, v in pairs(t) do for k, v in pairs(t) do
@ -131,6 +163,10 @@ function table.index_of(t, value)
return nil return nil
end end
--- Finds the first element that satisfies a predicate
-- @param t table to search
-- @param predicate function(value, key, table) -> boolean
-- @return value, key of first matching element, or nil
function table.find(t, predicate) function table.find(t, predicate)
if type(t) ~= "table" then error("table.find: first argument must be a table", 2) end if type(t) ~= "table" then error("table.find: first argument must be a table", 2) end
if type(predicate) ~= "function" then error("table.find: second argument must be a function", 2) end if type(predicate) ~= "function" then error("table.find: second argument must be a function", 2) end
@ -141,6 +177,10 @@ function table.find(t, predicate)
return nil return nil
end end
--- Finds the key of the first element that satisfies a predicate
-- @param t table to search
-- @param predicate function(value, key, table) -> boolean
-- @return key of first matching element, or nil
function table.find_index(t, predicate) function table.find_index(t, predicate)
if type(t) ~= "table" then error("table.find_index: first argument must be a table", 2) end if type(t) ~= "table" then error("table.find_index: first argument must be a table", 2) end
if type(predicate) ~= "function" then error("table.find_index: second argument must be a function", 2) end if type(predicate) ~= "function" then error("table.find_index: second argument must be a function", 2) end
@ -151,6 +191,10 @@ function table.find_index(t, predicate)
return nil return nil
end end
--- Counts elements matching a value or predicate
-- @param t table to search
-- @param value_or_predicate value to match or function(value, key, table) -> boolean
-- @return number of matching elements
function table.count(t, value_or_predicate) function table.count(t, value_or_predicate)
if type(t) ~= "table" then error("table.count: first argument must be a table", 2) end if type(t) ~= "table" then error("table.count: first argument must be a table", 2) end
@ -167,6 +211,10 @@ function table.count(t, value_or_predicate)
return count return count
end end
--- Filters elements that satisfy a predicate
-- @param t table to filter
-- @param predicate function(value, key, table) -> boolean
-- @return new table with elements that pass the test
function table.filter(t, predicate) function table.filter(t, predicate)
if type(t) ~= "table" then error("table.filter: first argument must be a table", 2) end if type(t) ~= "table" then error("table.filter: first argument must be a table", 2) end
if type(predicate) ~= "function" then error("table.filter: second argument must be a function", 2) end if type(predicate) ~= "function" then error("table.filter: second argument must be a function", 2) end
@ -195,6 +243,10 @@ function table.filter(t, predicate)
return result return result
end end
--- Filters elements that don't satisfy a predicate
-- @param t table to filter
-- @param predicate function(value, key, table) -> boolean
-- @return new table with elements that fail the test
function table.reject(t, predicate) function table.reject(t, predicate)
if type(t) ~= "table" then error("table.reject: first argument must be a table", 2) end if type(t) ~= "table" then error("table.reject: first argument must be a table", 2) end
if type(predicate) ~= "function" then error("table.reject: second argument must be a function", 2) end if type(predicate) ~= "function" then error("table.reject: second argument must be a function", 2) end
@ -202,6 +254,10 @@ function table.reject(t, predicate)
return table.filter(t, function(v, k, tbl) return not predicate(v, k, tbl) end) return table.filter(t, function(v, k, tbl) return not predicate(v, k, tbl) end)
end end
--- Transforms each element using a function
-- @param t table to transform
-- @param transformer function(value, key, table) -> new_value
-- @return new table with transformed elements
function table.map(t, transformer) function table.map(t, transformer)
if type(t) ~= "table" then error("table.map: first argument must be a table", 2) end if type(t) ~= "table" then error("table.map: first argument must be a table", 2) end
if type(transformer) ~= "function" then error("table.map: second argument must be a function", 2) end if type(transformer) ~= "function" then error("table.map: second argument must be a function", 2) end
@ -213,6 +269,10 @@ function table.map(t, transformer)
return result return result
end end
--- Transforms values while preserving keys
-- @param t table to transform
-- @param transformer function(value, key, table) -> new_value
-- @return new table with transformed values
function table.map_values(t, transformer) function table.map_values(t, transformer)
if type(t) ~= "table" then error("table.map_values: first argument must be a table", 2) end if type(t) ~= "table" then error("table.map_values: first argument must be a table", 2) end
if type(transformer) ~= "function" then error("table.map_values: second argument must be a function", 2) end if type(transformer) ~= "function" then error("table.map_values: second argument must be a function", 2) end
@ -224,6 +284,10 @@ function table.map_values(t, transformer)
return result return result
end end
--- Transforms keys while preserving values
-- @param t table to transform
-- @param transformer function(key, value, table) -> new_key
-- @return new table with transformed keys
function table.map_keys(t, transformer) function table.map_keys(t, transformer)
if type(t) ~= "table" then error("table.map_keys: first argument must be a table", 2) end if type(t) ~= "table" then error("table.map_keys: first argument must be a table", 2) end
if type(transformer) ~= "function" then error("table.map_keys: second argument must be a function", 2) end if type(transformer) ~= "function" then error("table.map_keys: second argument must be a function", 2) end
@ -236,6 +300,11 @@ function table.map_keys(t, transformer)
return result return result
end end
--- Reduces table to a single value using an accumulator function
-- @param t table to reduce
-- @param reducer function(accumulator, value, key, table) -> new_accumulator
-- @param initial optional initial accumulator value
-- @return final accumulator value
function table.reduce(t, reducer, initial) function table.reduce(t, reducer, initial)
if type(t) ~= "table" then error("table.reduce: first argument must be a table", 2) end if type(t) ~= "table" then error("table.reduce: first argument must be a table", 2) end
if type(reducer) ~= "function" then error("table.reduce: second argument must be a function", 2) end if type(reducer) ~= "function" then error("table.reduce: second argument must be a function", 2) end
@ -259,6 +328,9 @@ function table.reduce(t, reducer, initial)
return accumulator return accumulator
end end
--- Sums all numeric values in a table
-- @param t table containing numbers
-- @return sum of all values
function table.sum(t) function table.sum(t)
if type(t) ~= "table" then error("table.sum: argument must be a table", 2) end if type(t) ~= "table" then error("table.sum: argument must be a table", 2) end
local total = 0 local total = 0
@ -269,6 +341,9 @@ function table.sum(t)
return total return total
end end
--- Multiplies all numeric values in a table
-- @param t table containing numbers
-- @return product of all values
function table.product(t) function table.product(t)
if type(t) ~= "table" then error("table.product: argument must be a table", 2) end if type(t) ~= "table" then error("table.product: argument must be a table", 2) end
local result = 1 local result = 1
@ -279,6 +354,9 @@ function table.product(t)
return result return result
end end
--- Finds the minimum numeric value in a table
-- @param t table containing numbers
-- @return minimum value
function table.min(t) function table.min(t)
if type(t) ~= "table" then error("table.min: argument must be a table", 2) end if type(t) ~= "table" then error("table.min: argument must be a table", 2) end
if table.is_empty(t) then error("table.min: table is empty", 2) end if table.is_empty(t) then error("table.min: table is empty", 2) end
@ -293,6 +371,9 @@ function table.min(t)
return min_val return min_val
end end
--- Finds the maximum numeric value in a table
-- @param t table containing numbers
-- @return maximum value
function table.max(t) function table.max(t)
if type(t) ~= "table" then error("table.max: argument must be a table", 2) end if type(t) ~= "table" then error("table.max: argument must be a table", 2) end
if table.is_empty(t) then error("table.max: table is empty", 2) end if table.is_empty(t) then error("table.max: table is empty", 2) end
@ -307,12 +388,19 @@ function table.max(t)
return max_val return max_val
end end
--- Calculates the average of all numeric values
-- @param t table containing numbers
-- @return average value
function table.average(t) function table.average(t)
if type(t) ~= "table" then error("table.average: argument must be a table", 2) end if type(t) ~= "table" then error("table.average: argument must be a table", 2) end
if table.is_empty(t) then error("table.average: table is empty", 2) end if table.is_empty(t) then error("table.average: table is empty", 2) end
return table.sum(t) / table.size(t) return table.sum(t) / table.size(t)
end end
--- Tests if all elements satisfy a predicate or are truthy
-- @param t table to test
-- @param predicate optional function(value, key, table) -> boolean
-- @return true if all elements pass the test
function table.all(t, predicate) function table.all(t, predicate)
if type(t) ~= "table" then error("table.all: first argument must be a table", 2) end if type(t) ~= "table" then error("table.all: first argument must be a table", 2) end
@ -329,6 +417,10 @@ function table.all(t, predicate)
return true return true
end end
--- Tests if any element satisfies a predicate or is truthy
-- @param t table to test
-- @param predicate optional function(value, key, table) -> boolean
-- @return true if at least one element passes the test
function table.any(t, predicate) function table.any(t, predicate)
if type(t) ~= "table" then error("table.any: first argument must be a table", 2) end if type(t) ~= "table" then error("table.any: first argument must be a table", 2) end
@ -345,11 +437,18 @@ function table.any(t, predicate)
return false return false
end end
--- Tests if no element satisfies a predicate or is truthy
-- @param t table to test
-- @param predicate optional function(value, key, table) -> boolean
-- @return true if no elements pass the test
function table.none(t, predicate) function table.none(t, predicate)
if type(t) ~= "table" then error("table.none: first argument must be a table", 2) end if type(t) ~= "table" then error("table.none: first argument must be a table", 2) end
return not table.any(t, predicate) return not table.any(t, predicate)
end end
--- Removes duplicate values from a table
-- @param t table to deduplicate
-- @return new table with unique values
function table.unique(t) function table.unique(t)
if type(t) ~= "table" then error("table.unique: argument must be a table", 2) end if type(t) ~= "table" then error("table.unique: argument must be a table", 2) end
@ -375,6 +474,10 @@ function table.unique(t)
return result return result
end end
--- Returns elements common to both tables
-- @param t1 first table
-- @param t2 second table
-- @return new table with intersecting values
function table.intersection(t1, t2) function table.intersection(t1, t2)
if type(t1) ~= "table" then error("table.intersection: first argument must be a table", 2) end if type(t1) ~= "table" then error("table.intersection: first argument must be a table", 2) end
if type(t2) ~= "table" then error("table.intersection: second argument must be a table", 2) end if type(t2) ~= "table" then error("table.intersection: second argument must be a table", 2) end
@ -402,6 +505,10 @@ function table.intersection(t1, t2)
return result return result
end end
--- Combines two tables, keeping all unique values
-- @param t1 first table
-- @param t2 second table
-- @return new table with all unique values from both tables
function table.union(t1, t2) function table.union(t1, t2)
if type(t1) ~= "table" then error("table.union: first argument must be a table", 2) end if type(t1) ~= "table" then error("table.union: first argument must be a table", 2) end
if type(t2) ~= "table" then error("table.union: second argument must be a table", 2) end if type(t2) ~= "table" then error("table.union: second argument must be a table", 2) end
@ -425,6 +532,10 @@ function table.union(t1, t2)
return result return result
end end
--- Returns elements in first table but not in second
-- @param t1 first table
-- @param t2 second table
-- @return new table with values from t1 that are not in t2
function table.difference(t1, t2) function table.difference(t1, t2)
if type(t1) ~= "table" then error("table.difference: first argument must be a table", 2) end if type(t1) ~= "table" then error("table.difference: first argument must be a table", 2) end
if type(t2) ~= "table" then error("table.difference: second argument must be a table", 2) end if type(t2) ~= "table" then error("table.difference: second argument must be a table", 2) end
@ -437,6 +548,9 @@ function table.difference(t1, t2)
return table.filter(t1, function(v) return not set2[v] end) return table.filter(t1, function(v) return not set2[v] end)
end end
--- Reverses the order of elements in an array
-- @param t array to reverse
-- @return new array with elements in reverse order
function table.reverse(t) function table.reverse(t)
if type(t) ~= "table" then error("table.reverse: argument must be a table", 2) end if type(t) ~= "table" then error("table.reverse: argument must be a table", 2) end
if not table.is_array(t) then error("table.reverse: argument must be an array", 2) end if not table.is_array(t) then error("table.reverse: argument must be an array", 2) end
@ -449,6 +563,9 @@ function table.reverse(t)
return result return result
end end
--- Randomly shuffles elements in an array
-- @param t array to shuffle
-- @return new array with elements in random order
function table.shuffle(t) function table.shuffle(t)
if type(t) ~= "table" then error("table.shuffle: argument must be a table", 2) end if type(t) ~= "table" then error("table.shuffle: argument must be a table", 2) end
if not table.is_array(t) then error("table.shuffle: argument must be an array", 2) end if not table.is_array(t) then error("table.shuffle: argument must be an array", 2) end
@ -466,6 +583,10 @@ function table.shuffle(t)
return result return result
end end
--- Rotates array elements by a number of positions
-- @param t array to rotate
-- @param positions number of positions to rotate (positive = right, negative = left)
-- @return new array with rotated elements
function table.rotate(t, positions) function table.rotate(t, positions)
if type(t) ~= "table" then error("table.rotate: first argument must be a table", 2) end if type(t) ~= "table" then error("table.rotate: first argument must be a table", 2) end
if not table.is_array(t) then error("table.rotate: first argument must be an array", 2) end if not table.is_array(t) then error("table.rotate: first argument must be an array", 2) end
@ -488,6 +609,11 @@ function table.rotate(t, positions)
return result return result
end end
--- Extracts a section of an array
-- @param t array to slice
-- @param start_idx starting index (inclusive)
-- @param end_idx ending index (inclusive, optional)
-- @return new array containing the slice
function table.slice(t, start_idx, end_idx) function table.slice(t, start_idx, end_idx)
if type(t) ~= "table" then error("table.slice: first argument must be a table", 2) end if type(t) ~= "table" then error("table.slice: first argument must be a table", 2) end
if not table.is_array(t) then error("table.slice: first argument must be an array", 2) end if not table.is_array(t) then error("table.slice: first argument must be an array", 2) end
@ -513,6 +639,12 @@ function table.slice(t, start_idx, end_idx)
return result return result
end end
--- Modifies an array by removing elements and/or adding new ones
-- @param t array to modify
-- @param start_idx starting index for modification
-- @param delete_count number of elements to remove
-- @param ... elements to insert at start_idx
-- @return array of removed elements
function table.splice(t, start_idx, delete_count, ...) function table.splice(t, start_idx, delete_count, ...)
if type(t) ~= "table" then error("table.splice: first argument must be a table", 2) end if type(t) ~= "table" then error("table.splice: first argument must be a table", 2) end
if not table.is_array(t) then error("table.splice: first argument must be an array", 2) end if not table.is_array(t) then error("table.splice: first argument must be an array", 2) end
@ -564,6 +696,10 @@ function table.splice(t, start_idx, delete_count, ...)
return deleted return deleted
end end
--- Sorts an array by a key function
-- @param t array to sort
-- @param key_func function to extract sort key from each element
-- @return new sorted array
function table.sort_by(t, key_func) function table.sort_by(t, key_func)
if type(t) ~= "table" then error("table.sort_by: first argument must be a table", 2) end if type(t) ~= "table" then error("table.sort_by: first argument must be a table", 2) end
if not table.is_array(t) then error("table.sort_by: first argument must be an array", 2) end if not table.is_array(t) then error("table.sort_by: first argument must be an array", 2) end
@ -576,6 +712,10 @@ function table.sort_by(t, key_func)
return result return result
end end
--- Checks if an array is sorted according to a comparator
-- @param t array to check
-- @param comp optional comparator function
-- @return true if array is sorted
function table.is_sorted(t, comp) function table.is_sorted(t, comp)
if type(t) ~= "table" then error("table.is_sorted: first argument must be a table", 2) end if type(t) ~= "table" then error("table.is_sorted: first argument must be a table", 2) end
if not table.is_array(t) then error("table.is_sorted: first argument must be an array", 2) end if not table.is_array(t) then error("table.is_sorted: first argument must be an array", 2) end
@ -591,6 +731,9 @@ function table.is_sorted(t, comp)
return true return true
end end
--- Returns an array of all keys in a table
-- @param t table to extract keys from
-- @return array of keys
function table.keys(t) function table.keys(t)
if type(t) ~= "table" then error("table.keys: argument must be a table", 2) end if type(t) ~= "table" then error("table.keys: argument must be a table", 2) end
@ -601,6 +744,9 @@ function table.keys(t)
return result return result
end end
--- Returns an array of all values in a table
-- @param t table to extract values from
-- @return array of values
function table.values(t) function table.values(t)
if type(t) ~= "table" then error("table.values: argument must be a table", 2) end if type(t) ~= "table" then error("table.values: argument must be a table", 2) end
@ -611,6 +757,9 @@ function table.values(t)
return result return result
end end
--- Returns an array of [key, value] pairs
-- @param t table to convert to pairs
-- @return array of [key, value] arrays
function table.pairs(t) function table.pairs(t)
if type(t) ~= "table" then error("table.pairs: argument must be a table", 2) end if type(t) ~= "table" then error("table.pairs: argument must be a table", 2) end
@ -621,6 +770,9 @@ function table.pairs(t)
return result return result
end end
--- Merges multiple tables into a new table
-- @param ... tables to merge
-- @return new table with all key-value pairs
function table.merge(...) function table.merge(...)
local tables = {...} local tables = {...}
if #tables == 0 then return {} end if #tables == 0 then return {} end
@ -640,6 +792,10 @@ function table.merge(...)
return result return result
end end
--- Extends the first table with key-value pairs from other tables
-- @param t1 table to extend
-- @param ... tables to merge into t1
-- @return t1 (modified)
function table.extend(t1, ...) function table.extend(t1, ...)
if type(t1) ~= "table" then error("table.extend: first argument must be a table", 2) end if type(t1) ~= "table" then error("table.extend: first argument must be a table", 2) end
@ -658,6 +814,9 @@ function table.extend(t1, ...)
return t1 return t1
end end
--- Creates a table with keys and values swapped
-- @param t table to invert
-- @return new table with values as keys and keys as values
function table.invert(t) function table.invert(t)
if type(t) ~= "table" then error("table.invert: argument must be a table", 2) end if type(t) ~= "table" then error("table.invert: argument must be a table", 2) end
@ -668,6 +827,10 @@ function table.invert(t)
return result return result
end end
--- Creates a new table with only specified keys
-- @param t table to pick from
-- @param ... keys to include
-- @return new table with only specified keys
function table.pick(t, ...) function table.pick(t, ...)
if type(t) ~= "table" then error("table.pick: first argument must be a table", 2) end if type(t) ~= "table" then error("table.pick: first argument must be a table", 2) end
@ -683,6 +846,10 @@ function table.pick(t, ...)
return result return result
end end
--- Creates a new table excluding specified keys
-- @param t table to omit from
-- @param ... keys to exclude
-- @return new table without specified keys
function table.omit(t, ...) function table.omit(t, ...)
if type(t) ~= "table" then error("table.omit: first argument must be a table", 2) end if type(t) ~= "table" then error("table.omit: first argument must be a table", 2) end
@ -701,6 +868,10 @@ function table.omit(t, ...)
return result return result
end end
--- Deep equality comparison between two tables
-- @param t1 first table
-- @param t2 second table
-- @return true if tables are deeply equal
function table.deep_equals(t1, t2) function table.deep_equals(t1, t2)
if type(t1) ~= "table" then error("table.deep_equals: first argument must be a table", 2) end if type(t1) ~= "table" then error("table.deep_equals: first argument must be a table", 2) end
if type(t2) ~= "table" then error("table.deep_equals: second argument must be a table", 2) end if type(t2) ~= "table" then error("table.deep_equals: second argument must be a table", 2) end
@ -739,6 +910,10 @@ function table.deep_equals(t1, t2)
return equals_recursive(t1, t2, {}) return equals_recursive(t1, t2, {})
end end
--- Flattens nested arrays to specified depth
-- @param t array to flatten
-- @param depth maximum depth to flatten (default 1)
-- @return new flattened array
function table.flatten(t, depth) function table.flatten(t, depth)
if type(t) ~= "table" then error("table.flatten: first argument must be a table", 2) end if type(t) ~= "table" then error("table.flatten: first argument must be a table", 2) end
if not table.is_array(t) then error("table.flatten: first argument must be an array", 2) end if not table.is_array(t) then error("table.flatten: first argument must be an array", 2) end
@ -766,6 +941,9 @@ function table.flatten(t, depth)
return flatten_recursive(t, depth) return flatten_recursive(t, depth)
end end
--- Deep merges multiple tables, combining nested tables
-- @param ... tables to deep merge
-- @return new table with deeply merged contents
function table.deep_merge(...) function table.deep_merge(...)
local tables = {...} local tables = {...}
if #tables == 0 then return {} end if #tables == 0 then return {} end
@ -795,6 +973,10 @@ function table.deep_merge(...)
return result return result
end end
--- Splits an array into chunks of specified size
-- @param t array to chunk
-- @param size size of each chunk
-- @return array of chunks
function table.chunk(t, size) function table.chunk(t, size)
if type(t) ~= "table" then error("table.chunk: first argument must be a table", 2) end if type(t) ~= "table" then error("table.chunk: first argument must be a table", 2) end
if not table.is_array(t) then error("table.chunk: first argument must be an array", 2) end if not table.is_array(t) then error("table.chunk: first argument must be an array", 2) end
@ -816,6 +998,10 @@ function table.chunk(t, size)
return result return result
end end
--- Splits a table into two based on a predicate
-- @param t table to partition
-- @param predicate function(value, key, table) -> boolean
-- @return two tables: elements that pass and elements that fail
function table.partition(t, predicate) function table.partition(t, predicate)
if type(t) ~= "table" then error("table.partition: first argument must be a table", 2) end if type(t) ~= "table" then error("table.partition: first argument must be a table", 2) end
if type(predicate) ~= "function" then error("table.partition: second argument must be a function", 2) end if type(predicate) ~= "function" then error("table.partition: second argument must be a function", 2) end
@ -843,6 +1029,10 @@ function table.partition(t, predicate)
return truthy, falsy return truthy, falsy
end end
--- Groups table elements by a key function
-- @param t table to group
-- @param key_func function(value, key, table) -> group_key
-- @return table where keys are group keys and values are grouped elements
function table.group_by(t, key_func) function table.group_by(t, key_func)
if type(t) ~= "table" then error("table.group_by: first argument must be a table", 2) end if type(t) ~= "table" then error("table.group_by: first argument must be a table", 2) end
if type(key_func) ~= "function" then error("table.group_by: second argument must be a function", 2) end if type(key_func) ~= "function" then error("table.group_by: second argument must be a function", 2) end
@ -865,6 +1055,9 @@ function table.group_by(t, key_func)
return result return result
end end
--- Combines multiple arrays element-wise into tuples
-- @param ... arrays to zip together
-- @return array of tuples
function table.zip(...) function table.zip(...)
local arrays = {...} local arrays = {...}
if #arrays == 0 then error("table.zip: at least one argument required", 2) end if #arrays == 0 then error("table.zip: at least one argument required", 2) end
@ -895,6 +1088,9 @@ function table.zip(...)
return result return result
end end
--- Removes falsy values (nil and false) from a table
-- @param t table to compact
-- @return new table with only truthy values
function table.compact(t) function table.compact(t)
if type(t) ~= "table" then error("table.compact: argument must be a table", 2) end if type(t) ~= "table" then error("table.compact: argument must be a table", 2) end
@ -925,6 +1121,10 @@ function table.compact(t)
end end
end end
--- Returns a random sample of elements from an array
-- @param t array to sample from
-- @param n number of elements to sample (default 1)
-- @return array with sampled elements
function table.sample(t, n) function table.sample(t, n)
if type(t) ~= "table" then error("table.sample: first argument must be a table", 2) end if type(t) ~= "table" then error("table.sample: first argument must be a table", 2) end
if not table.is_array(t) then error("table.sample: first argument must be an array", 2) end if not table.is_array(t) then error("table.sample: first argument must be an array", 2) end
@ -940,6 +1140,11 @@ function table.sample(t, n)
return table.slice(shuffled, 1, n) return table.slice(shuffled, 1, n)
end end
--- Folds a table using an accumulator function
-- @param t table to fold
-- @param folder function(accumulator, value, key, table) -> new_accumulator
-- @param initial initial accumulator value
-- @return final accumulator value
function table.fold(t, folder, initial) function table.fold(t, folder, initial)
if type(t) ~= "table" then error("table.fold: first argument must be a table", 2) end if type(t) ~= "table" then error("table.fold: first argument must be a table", 2) end
if type(folder) ~= "function" then error("table.fold: second argument must be a function", 2) end if type(folder) ~= "function" then error("table.fold: second argument must be a function", 2) end

View File

@ -883,5 +883,29 @@ test("Statistical Analysis", function()
assert_close(83.4, class_average, 0.1) assert_close(83.4, class_average, 0.1)
end) end)
test("Table Metatable Method Chaining", function()
local t = {1, 2, 3, 4, 5}
-- Check if methods are available directly on table instances
assert_equal("function", type(t.filter), "table should have filter method via metatable")
assert_equal("function", type(t.map), "table should have map method via metatable")
assert_equal("function", type(t.length), "table should have length method via metatable")
-- Test actual method chaining
local result = t:filter(function(v) return v > 2 end)
:map(function(v) return v * 2 end)
assert_table_equal({6, 8, 10}, result)
-- Test chaining with method calls
local nums = {1, 2, 3, 4, 5}
local sum = nums:sum()
assert_equal(15, sum)
local sizes = {a = 1, b = 2}
local size = sizes:size()
assert_equal(2, size)
end)
summary() summary()
test_exit() test_exit()

View File

@ -1,3 +0,0 @@
{
"session:x5joQraQyEkfzzRMrcP4o8yK0xjgwtCW": "{\"todos\":[{\"text\":\"asdasd\",\"completed\":true,\"id\":\"1753414744_8147\",\"created_at\":1753414744},{\"text\":\"fsdf\",\"completed\":true,\"id\":\"1753414748_8147\",\"created_at\":1753414748},{\"text\":\"asdasd\",\"completed\":false,\"id\":\"1753415063_8147\",\"created_at\":1753415063},{\"id\":\"1753415066_8147\",\"completed\":false,\"text\":\"asdkjfhaslkjdhflkasjhdf\",\"created_at\":1753415066},{\"text\":\"alsdhnfpuihawepiufhbpioweHBFIOEWBSF\",\"completed\":false,\"id\":\"1753415069_8147\",\"created_at\":1753415069}]}"
}