Module:ArrayList

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)
	    -- compare groups
	    if a.group ~= b.group then
	        return a.group < b.group
	    end
	
	    -- if both items in same group, decide
	    -- comparison based on alpha_priority flag
	    if alpha_priority then
	        -- if letters come first, group 1 = letters
	        if a.group == 1 then  -- Both are alphabetic.
	            return a.raw:lower() < b.raw:lower()
	        elseif a.group == 2 then  -- Both are numeric.
	            return a.num < b.num
	        else  -- Group 3: special items.
	            return a.orig < b.orig
	        end
	    else
	        -- if numbers first, group 1 = numbers
	        if a.group == 1 then  -- Both are numeric.
	            return a.num < b.num
	        elseif a.group == 2 then  -- Both are alphabetic.
	            return a.raw:lower() < b.raw:lower()
	        else  -- Group 3: special items.
	            return a.orig < b.orig
	        end
	    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

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.