Module:ArrayList: Difference between revisions
Appearance
Content deleted Content added
refine min/max code |
attempt to add array sorting function |
||
Line 95: | Line 95: | ||
local delimiter = frame.args[3] or "," |
local delimiter = frame.args[3] or "," |
||
local operation = frame.args[4] |
local operation = frame.args[4] |
||
local nth = tonumber(frame.args[5]) -- Optional Nth occurrence argument |
|||
delimiter = escapePattern(delimiter) |
delimiter = escapePattern(delimiter) |
||
str = str:gsub("^%s*" .. delimiter .. "%s*(.-)%s*" .. delimiter .. "$", "%1") |
str = str:gsub("^%s*" .. delimiter .. "%s*(.-)%s*" .. delimiter .. "$", "%1") |
||
Line 127: | Line 126: | ||
return "void:unsupported" |
return "void:unsupported" |
||
end |
end |
||
end |
|||
-- Sorts array with options for reverse ("r") and alpha-first ("a"). |
|||
function p.sort(frame) |
|||
local str = frame.args[2] or "" |
|||
local delimiter = frame.args[3] or "," |
|||
local params = frame.args[4] or "" |
|||
local delim_pat = escapePattern(delimiter) |
|||
-- Determine sort options (check if params a or r expressed) |
|||
local reverse = params:find("r") and true or false |
|||
local alpha_priority = params:find("a") and true or false |
|||
local items = {} |
|||
local orig_index = 1 |
|||
-- Split string using delimiter. |
|||
for item in string.gmatch(str, "([^" .. delim_pat .. "]+)") do |
|||
item = item:match("^%s*(.-)%s*$") -- trim whitespace |
|||
local num = tonumber(item) |
|||
local isnum = (num ~= nil) |
|||
local isalpha = (not isnum and item:match("^[A-Za-z]+$")) and true or false |
|||
local group |
|||
if alpha_priority then |
|||
if isalpha then |
|||
group = 1 |
|||
elseif isnum then |
|||
group = 2 |
|||
else |
|||
group = 3 |
|||
end |
|||
else |
|||
if isnum then |
|||
group = 1 |
|||
elseif isalpha then |
|||
group = 2 |
|||
else |
|||
group = 3 |
|||
end |
|||
end |
|||
table.insert(items, { |
|||
raw = item, |
|||
num = num, |
|||
isnum = isnum, |
|||
isalpha = isalpha, |
|||
group = group, |
|||
orig = orig_index -- remember original order for special items |
|||
}) |
|||
orig_index = orig_index + 1 |
|||
end |
|||
table.sort(items, function(a, b) |
|||
-- First sort by group. |
|||
if a.group ~= b.group then |
|||
return a.group < b.group |
|||
end |
|||
-- For numbers (group 1), sort numerically. |
|||
if a.group == 1 then |
|||
return a.num < b.num |
|||
-- For alphabetic items (group 2), sort case‐insensitively. |
|||
elseif a.group == 2 then |
|||
return a.raw:lower() < b.raw:lower() |
|||
else |
|||
-- For special items (group 3) keep the original order. |
|||
return a.orig < b.orig |
|||
end |
|||
end) |
|||
-- Reverse order if requested |
|||
if reverse then |
|||
for i = 1, math.floor(#items / 2) do |
|||
items[i], items[#items - i + 1] = items[#items - i + 1], items[i] |
|||
end |
|||
end |
|||
-- Build output string |
|||
local output = {} |
|||
for _, v in ipairs(items) do |
|||
table.insert(output, v.raw) |
|||
end |
|||
return table.concat(output, delimiter) |
|||
end |
end |
||
Revision as of 19:05, 2 February 2025
local p = {}
-- Helper function to trim whitespace
local function trim(s)
return s:match("^%s*(.-)%s*$")
end
-- Escape special characters in the delimiter for pattern matching
local function escapePattern(str)
return str:gsub("([%^%$%(%)%%%.%[%]%*%+%?%-])", "%%%1")
end
-- Main function to call other functions dynamically
function p.main(frame)
local func = frame.args[1]
if p[func] then
return p[func](frame)
else
return "void:notfound " .. tostring(func)
end
end
-- Count occurrences of delimiter in a string
function p.count(frame)
local str = frame.args[2] or ""
local delimiter = frame.args[3] or ","
local nostrip = frame.args["nostrip"]
delimiter = escapePattern(delimiter)
-- If nostrip is not set to "true", strip leading/trailing delimiters
if nostrip ~= "true" then
-- Remove leading and trailing delimiters (along with any surrounding whitespace)
str = str:gsub("^%s*" .. delimiter .. "%s*", ""):gsub("%s*" .. delimiter .. "%s*$", "")
-- Normalize internal consecutive delimiters to a single delimiter (replace ",," with ",")
str = str:gsub("%s*" .. delimiter .. "%s*" .. delimiter .. "%s*", delimiter)
end
local count = select(2, str:gsub(delimiter, ""))
return count + 1
end
-- Get the Nth item in a delimited string, supporting negative indices
function p.get(frame)
local str = frame.args[2] or ""
local delimiter = frame.args[3] or ","
local index = frame.args[4]
delimiter = escapePattern(delimiter)
str = str:gsub("^%s*" .. delimiter .. "%s*(.-)%s*" .. delimiter .. "$", "%1")
local items = {}
for item in string.gmatch(str, "([^" .. delimiter .. "]+)") do
table.insert(items, trim(item))
end
if index == "last" then
index = #items
elseif index and tonumber(index) then
index = tonumber(index)
if index < 0 then
index = #items + index + 1
end
else
return "void:invalid"
end
return items[index] or "void:outrange"
end
-- Find the position of the Nth occurrence of a matching item in a delimited string
function p.pos(frame)
local str = frame.args[2] or ""
local delimiter = frame.args[3] or ","
local item = frame.args[4] or ""
local occurrence = tonumber(frame.args[5])
delimiter = escapePattern(delimiter)
str = str:gsub("^%s*" .. delimiter .. "%s*(.-)%s*" .. delimiter .. "$", "%1")
local positions = {}
local index = 1
for subitem in string.gmatch(str, "([^" .. delimiter .. "]+)") do
subitem = trim(subitem)
if subitem == item then
table.insert(positions, index)
end
index = index + 1
end
if not occurrence then
return #positions > 0 and table.concat(positions, ",") or "void:nomatch"
else
return positions[occurrence] or -1
end
end
-- Perform mathematical operations on numeric array items
function p.math(frame)
local str = frame.args[2] or ""
local delimiter = frame.args[3] or ","
local operation = frame.args[4]
delimiter = escapePattern(delimiter)
str = str:gsub("^%s*" .. delimiter .. "%s*(.-)%s*" .. delimiter .. "$", "%1")
local items = {}
for item in string.gmatch(str, "([^" .. delimiter .. "]+)") do
local number = tonumber(trim(item))
if number then
table.insert(items, number)
else
return "void:isalpha"
end
end
if #items == 0 then
return "void:nonumeric"
elseif operation == "sum" then
local total = 0
for _, num in ipairs(items) do
total = total + num
end
return total
elseif operation == "min" or operation == "max" then
local extreme = items[1]
local comparison = operation == "min" and function(a, b) return a < b end or function(a, b) return a > b end
for _, num in ipairs(items) do
if comparison(num, extreme) then
extreme = num
end
end
return extreme
else
return "void:unsupported"
end
end
-- Sorts array with options for reverse ("r") and alpha-first ("a").
function p.sort(frame)
local str = frame.args[2] or ""
local delimiter = frame.args[3] or ","
local params = frame.args[4] or ""
local delim_pat = escapePattern(delimiter)
-- Determine sort options (check if params a or r expressed)
local reverse = params:find("r") and true or false
local alpha_priority = params:find("a") and true or false
local items = {}
local orig_index = 1
-- Split string using delimiter.
for item in string.gmatch(str, "([^" .. delim_pat .. "]+)") do
item = item:match("^%s*(.-)%s*$") -- trim whitespace
local num = tonumber(item)
local isnum = (num ~= nil)
local isalpha = (not isnum and item:match("^[A-Za-z]+$")) and true or false
local group
if alpha_priority then
if isalpha then
group = 1
elseif isnum then
group = 2
else
group = 3
end
else
if isnum then
group = 1
elseif isalpha then
group = 2
else
group = 3
end
end
table.insert(items, {
raw = item,
num = num,
isnum = isnum,
isalpha = isalpha,
group = group,
orig = orig_index -- remember original order for special items
})
orig_index = orig_index + 1
end
table.sort(items, function(a, b)
-- First sort by group.
if a.group ~= b.group then
return a.group < b.group
end
-- For numbers (group 1), sort numerically.
if a.group == 1 then
return a.num < b.num
-- For alphabetic items (group 2), sort case‐insensitively.
elseif a.group == 2 then
return a.raw:lower() < b.raw:lower()
else
-- For special items (group 3) keep the original order.
return a.orig < b.orig
end
end)
-- Reverse order if requested
if reverse then
for i = 1, math.floor(#items / 2) do
items[i], items[#items - i + 1] = items[#items - i + 1], items[i]
end
end
-- Build output string
local output = {}
for _, v in ipairs(items) do
table.insert(output, v.raw)
end
return table.concat(output, delimiter)
end
return p