--[[ table.lua - Extended table library functions ]]-- local table_ext = {} -- ====================================================================== -- SET OPERATIONS -- ====================================================================== -- Remove duplicate values (like array_unique) function table_ext.unique(t) if type(t) ~= "table" then return {} end local seen = {} local result = {} for _, v in ipairs(t) do if not seen[v] then seen[v] = true table.insert(result, v) end end return result end -- Return items in first table that are present in all other tables (like array_intersect) function table_ext.intersect(t1, ...) if type(t1) ~= "table" then return {} end local args = {...} local result = {} -- Convert all tables to sets for O(1) lookups local sets = {} for i, t in ipairs(args) do if type(t) ~= "table" then return {} end sets[i] = {} for _, v in ipairs(t) do sets[i][v] = true end end -- Check each element in t1 against all other tables for _, v in ipairs(t1) do local present_in_all = true for i = 1, #args do if not sets[i][v] then present_in_all = false break end end if present_in_all then table.insert(result, v) end end return result end -- Return items in first table that are not present in other tables (like array_diff) function table_ext.diff(t1, ...) if type(t1) ~= "table" then return {} end local args = {...} local result = {} -- Build unified set of elements from other tables local others = {} for _, t in ipairs(args) do if type(t) == "table" then for _, v in ipairs(t) do others[v] = true end end end -- Add elements from t1 that aren't in other tables for _, v in ipairs(t1) do if not others[v] then table.insert(result, v) end end return result end -- ====================================================================== -- SEARCH AND FILTERING -- ====================================================================== -- Check if value exists in table (like in_array) function table_ext.contains(t, value) if type(t) ~= "table" then return false end for _, v in ipairs(t) do if v == value then return true end end return false end -- Find key for a value (like array_search) function table_ext.find(t, value) if type(t) ~= "table" then return nil end for k, v in pairs(t) do if v == value then return k end end return nil end -- Filter table elements (like array_filter) function table_ext.filter(t, func) if type(t) ~= "table" or type(func) ~= "function" then return {} end local result = {} for k, v in pairs(t) do if func(v, k) then if type(k) == "number" and k % 1 == 0 and k > 0 then -- For array-like tables, maintain numerical indices table.insert(result, v) else -- For associative tables, preserve the key result[k] = v end end end return result end -- ====================================================================== -- TRANSFORMATION FUNCTIONS -- ====================================================================== -- Apply a function to all values (like array_map) function table_ext.map(t, func) if type(t) ~= "table" or type(func) ~= "function" then return {} end local result = {} for k, v in pairs(t) do if type(k) == "number" and k % 1 == 0 and k > 0 then -- For array-like tables, maintain numerical indices table.insert(result, func(v, k)) else -- For associative tables, preserve the key result[k] = func(v, k) end end return result end -- Reduce a table to a single value (like array_reduce) function table_ext.reduce(t, func, initial) if type(t) ~= "table" or type(func) ~= "function" then return initial end local result = initial for k, v in pairs(t) do if result == nil then result = v else result = func(result, v, k) end end return result end -- ====================================================================== -- ADVANCED OPERATIONS -- ====================================================================== -- Split table into chunks (like array_chunk) function table_ext.chunk(t, size) if type(t) ~= "table" or type(size) ~= "number" or size <= 0 then return {} end local result = {} local chunk = {} local count = 0 for _, v in ipairs(t) do count = count + 1 chunk[count] = v if count == size then table.insert(result, chunk) chunk = {} count = 0 end end -- Add the last chunk if it has any elements if count > 0 then table.insert(result, chunk) end return result end -- Extract a column from a table of tables (like array_column) function table_ext.column(t, column_key, index_key) if type(t) ~= "table" or column_key == nil then return {} end local result = {} for _, row in ipairs(t) do if type(row) == "table" and row[column_key] ~= nil then if index_key ~= nil and row[index_key] ~= nil then result[row[index_key]] = row[column_key] else table.insert(result, row[column_key]) end end end return result end -- Merge tables (like array_merge, but preserves keys) function table_ext.merge(...) local result = {} for _, t in ipairs({...}) do if type(t) == "table" then for k, v in pairs(t) do if type(k) == "number" and k % 1 == 0 and k > 0 then -- For array-like tables, append values table.insert(result, v) else -- For associative tables, overwrite with latest value result[k] = v end end end end return result end -- ====================================================================== -- KEY MANIPULATION -- ====================================================================== -- Exchange keys with values (like array_flip) function table_ext.flip(t) if type(t) ~= "table" then return {} end local result = {} for k, v in pairs(t) do if type(v) == "string" or type(v) == "number" then result[v] = k end end return result end -- Get all keys from a table (like array_keys) function table_ext.keys(t) if type(t) ~= "table" then return {} end local result = {} for k, _ in pairs(t) do table.insert(result, k) end return result end -- Get all values from a table (like array_values) function table_ext.values(t) if type(t) ~= "table" then return {} end local result = {} for _, v in pairs(t) do table.insert(result, v) end return result end -- ====================================================================== -- STATISTICAL FUNCTIONS -- ====================================================================== -- Sum all values (like array_sum) function table_ext.sum(t) if type(t) ~= "table" then return 0 end local sum = 0 for _, v in pairs(t) do if type(v) == "number" then sum = sum + v end end return sum end -- Multiply all values (like array_product) function table_ext.product(t) if type(t) ~= "table" then return 0 end local product = 1 local has_number = false for _, v in pairs(t) do if type(v) == "number" then product = product * v has_number = true end end return has_number and product or 0 end -- Count value occurrences (like array_count_values) function table_ext.count_values(t) if type(t) ~= "table" then return {} end local result = {} for _, v in pairs(t) do if type(v) == "string" or type(v) == "number" then result[v] = (result[v] or 0) + 1 end end return result end -- ====================================================================== -- CREATION HELPERS -- ====================================================================== -- Create a table with a range of values (like range) function table_ext.range(start, stop, step) if type(start) ~= "number" then return {} end step = step or 1 local result = {} if not stop then stop = start start = 1 end if (step > 0 and start > stop) or (step < 0 and start < stop) then return {} end local i = start while (step > 0 and i <= stop) or (step < 0 and i >= stop) do table.insert(result, i) i = i + step end return result end -- Fill a table with a value (like array_fill) function table_ext.fill(start_index, count, value) if type(start_index) ~= "number" or type(count) ~= "number" or count < 0 then return {} end local result = {} for i = 0, count - 1 do result[start_index + i] = value end return result end -- ====================================================================== -- ADDITIONAL USEFUL FUNCTIONS -- ====================================================================== -- Reverse a table (array part only) function table_ext.reverse(t) if type(t) ~= "table" then return {} end local result = {} local count = #t for i = count, 1, -1 do table.insert(result, t[i]) end return result end -- Get the max value in a table function table_ext.max(t) if type(t) ~= "table" or #t == 0 then return nil end local max = t[1] for i = 2, #t do if t[i] > max then max = t[i] end end return max end -- Get the min value in a table function table_ext.min(t) if type(t) ~= "table" or #t == 0 then return nil end local min = t[1] for i = 2, #t do if t[i] < min then min = t[i] end end return min end -- Check if all elements satisfy a condition function table_ext.all(t, func) if type(t) ~= "table" or type(func) ~= "function" then return false end for k, v in pairs(t) do if not func(v, k) then return false end end return true end -- Check if any element satisfies a condition function table_ext.any(t, func) if type(t) ~= "table" or type(func) ~= "function" then return false end for k, v in pairs(t) do if func(v, k) then return true end end return false end -- ====================================================================== -- TABLE UTILITIES -- ====================================================================== -- Check if table is empty function table_ext.is_empty(t) if type(t) ~= "table" then return true end return next(t) == nil end -- Get table length (works for both array and hash parts) function table_ext.size(t) if type(t) ~= "table" then return 0 end local count = 0 for _ in pairs(t) do count = count + 1 end return count end -- Get a slice of a table function table_ext.slice(t, start, stop) if type(t) ~= "table" then return {} end local len = #t start = start or 1 stop = stop or len -- Convert negative indices if start < 0 then start = len + start + 1 end if stop < 0 then stop = len + stop + 1 end -- Ensure bounds start = math.max(1, math.min(start, len + 1)) stop = math.max(0, math.min(stop, len)) local result = {} for i = start, stop do table.insert(result, t[i]) end return result end -- ====================================================================== -- SORTING FUNCTIONS -- ====================================================================== -- Sort array values (like sort) function table_ext.sort(t) if type(t) ~= "table" then return t end table.sort(t) return t end -- Sort array values in reverse order (like rsort) function table_ext.rsort(t) if type(t) ~= "table" then return t end table.sort(t, function(a, b) return a > b end) return t end -- Sort and maintain index association (like asort) function table_ext.asort(t) if type(t) ~= "table" then return t end local keys, result = {}, {} for k in pairs(t) do table.insert(keys, k) end table.sort(keys, function(a, b) return t[a] < t[b] end) for _, k in ipairs(keys) do result[k] = t[k] end return result end -- Sort in reverse order and maintain index association (like arsort) function table_ext.arsort(t) if type(t) ~= "table" then return t end local keys, result = {}, {} for k in pairs(t) do table.insert(keys, k) end table.sort(keys, function(a, b) return t[a] > t[b] end) for _, k in ipairs(keys) do result[k] = t[k] end return result end -- Sort by keys (like ksort) function table_ext.ksort(t) if type(t) ~= "table" then return t end local keys, result = {}, {} for k in pairs(t) do table.insert(keys, k) end table.sort(keys) for _, k in ipairs(keys) do result[k] = t[k] end return result end -- Sort by keys in reverse order (like krsort) function table_ext.krsort(t) if type(t) ~= "table" then return t end local keys, result = {}, {} for k in pairs(t) do table.insert(keys, k) end table.sort(keys, function(a, b) return a > b end) for _, k in ipairs(keys) do result[k] = t[k] end return result end -- Sort using custom comparison function (like usort) function table_ext.usort(t, compare_func) if type(t) ~= "table" or type(compare_func) ~= "function" then return t end table.sort(t, compare_func) return t end -- Sort maintaining keys using custom comparison function (like uasort) function table_ext.uasort(t, compare_func) if type(t) ~= "table" or type(compare_func) ~= "function" then return t end local keys, result = {}, {} for k in pairs(t) do table.insert(keys, k) end table.sort(keys, function(a, b) return compare_func(t[a], t[b]) end) for _, k in ipairs(keys) do result[k] = t[k] end return result end -- Sort by keys using custom comparison function (like uksort) function table_ext.uksort(t, compare_func) if type(t) ~= "table" or type(compare_func) ~= "function" then return t end local keys, result = {}, {} for k in pairs(t) do table.insert(keys, k) end table.sort(keys, compare_func) for _, k in ipairs(keys) do result[k] = t[k] end return result end -- Natural order sort (like natsort) function table_ext.natsort(t) if type(t) ~= "table" then return t end local function natural_compare(a, b) local function get_chunks(s) if type(s) ~= "string" then s = tostring(s) end local chunks = {} for num, alpha in s:gmatch("(%d+)([^%d]*)") do table.insert(chunks, {n=true, val=tonumber(num)}) if alpha ~= "" then table.insert(chunks, {n=false, val=alpha}) end end return chunks end local a_chunks = get_chunks(a) local b_chunks = get_chunks(b) for i = 1, math.min(#a_chunks, #b_chunks) do if a_chunks[i].n ~= b_chunks[i].n then return a_chunks[i].n -- numbers come before strings elseif a_chunks[i].val ~= b_chunks[i].val then if a_chunks[i].n then return a_chunks[i].val < b_chunks[i].val else return a_chunks[i].val < b_chunks[i].val end end end return #a_chunks < #b_chunks end table.sort(t, natural_compare) return t end -- Natural case-insensitive sort (like natcasesort) function table_ext.natcasesort(t) if type(t) ~= "table" then return t end local function case_insensitive_natural_compare(a, b) if type(a) == "string" and type(b) == "string" then return table_ext.natural_compare(a:lower(), b:lower()) else return table_ext.natural_compare(a, b) end end return table_ext.usort(t, case_insensitive_natural_compare) end -- ====================================================================== -- ARRAY MODIFICATION FUNCTIONS -- ====================================================================== -- Push one or more elements onto the end (like array_push) function table_ext.push(t, ...) if type(t) ~= "table" then return 0 end local count = 0 for _, v in ipairs({...}) do table.insert(t, v) count = count + 1 end return count end -- Pop the element off the end (like array_pop) function table_ext.pop(t) if type(t) ~= "table" or #t == 0 then return nil end local value = t[#t] t[#t] = nil return value end -- Shift an element off the beginning (like array_shift) function table_ext.shift(t) if type(t) ~= "table" or #t == 0 then return nil end local value = t[1] table.remove(t, 1) return value end -- Prepend elements to the beginning (like array_unshift) function table_ext.unshift(t, ...) if type(t) ~= "table" then return 0 end local args = {...} for i = #args, 1, -1 do table.insert(t, 1, args[i]) end return #t end -- Pad array to specified length (like array_pad) function table_ext.pad(t, size, value) if type(t) ~= "table" then return {} end local result = table_ext.deep_copy(t) local current_size = #result if size == current_size then return result end if size > current_size then -- Pad to the right for i = current_size + 1, size do result[i] = value end else -- Pad to the left (negative size) local abs_size = math.abs(size) if abs_size < current_size then local temp = {} for i = 1, abs_size do if i <= abs_size - current_size then temp[i] = value else temp[i] = result[i - (abs_size - current_size)] end end result = temp else -- Fill completely with padding value result = {} for i = 1, abs_size do result[i] = value end end end return result end -- Remove a portion and replace it (like array_splice) function table_ext.splice(t, offset, length, ...) if type(t) ~= "table" then return {} end local result = table_ext.deep_copy(t) local size = #result -- Handle negative offset if offset < 0 then offset = size + offset end -- Ensure offset is valid offset = math.max(1, math.min(offset, size + 1)) -- Handle negative or nil length if length == nil then length = size - offset + 1 elseif length < 0 then length = math.max(0, size - offset + length + 1) end -- Extract removed portion local removed = {} for i = offset, offset + length - 1 do if i <= size then table.insert(removed, result[i]) end end -- Remove portion from original for i = 1, length do table.remove(result, offset) end -- Insert replacement values local replacements = {...} for i = #replacements, 1, -1 do table.insert(result, offset, replacements[i]) end return removed, result end -- Randomize array order (like shuffle) function table_ext.shuffle(t) if type(t) ~= "table" then return t end local result = table_ext.deep_copy(t) local size = #result for i = size, 2, -1 do local j = math.random(i) result[i], result[j] = result[j], result[i] end return result end -- Pick random keys from array (like array_rand) function table_ext.rand(t, num_keys) if type(t) ~= "table" then return nil end local size = #t if size == 0 then return nil end num_keys = num_keys or 1 num_keys = math.min(num_keys, size) if num_keys <= 0 then return nil end if num_keys == 1 then return math.random(size) else local keys = {} local result = {} -- Create a list of all possible keys for i = 1, size do keys[i] = i end -- Select random keys for i = 1, num_keys do local j = math.random(#keys) table.insert(result, keys[j]) table.remove(keys, j) end table.sort(result) return result end end -- ====================================================================== -- ARRAY INSPECTION FUNCTIONS -- ====================================================================== -- Check if key exists (like array_key_exists) function table_ext.key_exists(key, t) if type(t) ~= "table" then return false end return t[key] ~= nil end -- Get the first key (like array_key_first) function table_ext.key_first(t) if type(t) ~= "table" then return nil end -- For array-like tables if #t > 0 then return 1 end -- For associative tables local first_key = nil for k in pairs(t) do first_key = k break end return first_key end -- Get the last key (like array_key_last) function table_ext.key_last(t) if type(t) ~= "table" then return nil end -- For array-like tables if #t > 0 then return #t end -- For associative tables (no guaranteed order, return any key) local last_key = nil for k in pairs(t) do last_key = k end return last_key end -- Check if table is a list (like array_is_list) function table_ext.is_list(t) if type(t) ~= "table" then return false end local count = 0 for k in pairs(t) do count = count + 1 if type(k) ~= "number" or k <= 0 or math.floor(k) ~= k or k > count then return false end end return true end -- ====================================================================== -- OTHER IMPORTANT FUNCTIONS -- ====================================================================== -- Create array with keys from one array, values from another (like array_combine) function table_ext.combine(keys, values) if type(keys) ~= "table" or type(values) ~= "table" then return {} end local result = {} local key_count = #keys local value_count = #values for i = 1, math.min(key_count, value_count) do result[keys[i]] = values[i] end return result end -- Replace elements from one array into another (like array_replace) function table_ext.replace(t, ...) if type(t) ~= "table" then return {} end local result = table_ext.deep_copy(t) for _, replacement in ipairs({...}) do if type(replacement) == "table" then for k, v in pairs(replacement) do result[k] = v end end end return result end -- Replace elements recursively (like array_replace_recursive) function table_ext.replace_recursive(t, ...) if type(t) ~= "table" then return {} end local result = table_ext.deep_copy(t) for _, replacement in ipairs({...}) do if type(replacement) == "table" then for k, v in pairs(replacement) do if type(v) == "table" and type(result[k]) == "table" then result[k] = table_ext.replace_recursive(result[k], v) else result[k] = v end end end end return result end -- Apply function to each element (like array_walk) function table_ext.walk(t, callback, user_data) if type(t) ~= "table" or type(callback) ~= "function" then return t end for k, v in pairs(t) do t[k] = callback(v, k, user_data) end return t end -- Apply function recursively (like array_walk_recursive) function table_ext.walk_recursive(t, callback, user_data) if type(t) ~= "table" or type(callback) ~= "function" then return t end for k, v in pairs(t) do if type(v) == "table" then table_ext.walk_recursive(v, callback, user_data) else t[k] = callback(v, k, user_data) end end return t end -- Sort multiple arrays (simplified array_multisort) function table_ext.multisort(...) local args = {...} if #args == 0 then return end -- First argument is the main table local main = args[1] if type(main) ~= "table" then return end -- Create a table of indices local indices = {} for i = 1, #main do indices[i] = i end -- Sort the indices based on the arrays table.sort(indices, function(a, b) for i = 1, #args do local arr = args[i] if type(arr) == "table" then if arr[a] ~= arr[b] then return arr[a] < arr[b] end end end return a < b end) -- Reorder all arrays based on sorted indices for i = 1, #args do local arr = args[i] if type(arr) == "table" then local temp = table_ext.deep_copy(arr) for j = 1, #indices do arr[j] = temp[indices[j]] end end end end -- Efficient deep copy function function table_ext.deep_copy(obj) if type(obj) ~= 'table' then return obj end local res = {} for k, v in pairs(obj) do res[k] = table_ext.deep_copy(v) end return res end -- ====================================================================== -- INSTALL EXTENSIONS INTO TABLE LIBRARY -- ====================================================================== for name, func in pairs(table) do table_ext[name] = func end return table_ext