Module:User:Erutuon/01

An experiment with a self-sorting table.

1: number one, 1: one, A: Ayy, B: Bee, a: ayy, b: bee, h: aitch, z: zee, Ж: Zh, ὦ: O

a: ayy, 1: one, A: Ayy, z: zee


local export = {}

local function sort(item1, item2)
	-- "number" < "string", so numbers will be sorted before strings.
	local type1, type2 = type(item1), type(item2)
	if type1 == type2 then
		return item1 < item2
	else
		return type1 < type2
	end
end

local function removeKey(t, keyToRemove)
	for i, key in pairs(t) do
		if key == keyToRemove then
			table.remove(t, i)
		end
	end
end

local function sortedTable(keySort)
	local mt = {}
	
	mt.table = {}
	mt.sortedKeys = {}
	mt.length = 0
	
	function mt.__index(t, key)
		local items = {
			sortedKeys = mt.sortedKeys,
			length = mt.length,
		}
		local item = items[key]
		
		if item == nil then
			return mt.table[key]
		else
			return item
		end
	end
	
	function mt.__newindex(t, key, value)
		if rawget(mt, key) then
			error("The key \"" .. tostring(key) .. "\" is reserved and cannot be changed.")
		end
		
		if value == nil then
			if rawget(mt.table, key) ~= nil then
				mt.length = mt.length - 1
				removeKey(mt.sortedKeys, key)
			end
		else
			local last = mt.sortedKeys[mt.length]
			mt.length = mt.length + 1
			rawset(mt.sortedKeys, mt.length, key)
			
			-- If key is ranked lower than last key in sortedKeys, do sorting.
			if keySort(key, last) then
				table.sort(mt.sortedKeys, keySort)
			end
		end
		
		rawset(mt.table, key, value)
	end
	
	return setmetatable({}, mt)
end
	
function sortedPairs(t)
	local i = 1
	local keys = mw.clone(t.sortedKeys)
	
	return function()
		local key = keys[i]
		if i <= t.length then
			i = i + 1
			return key, t[key]
		else
			return nil, nil
		end
	end
end

local oldpairs = pairs

local function pairs(t)
	if t.sortedKeys then
		return sortedPairs(t)
	else
		return oldpairs(t)
	end
end

local function printTable(t)
	local output = {}
	
	for key, value in pairs(t) do
		table.insert(output, key .. ": " .. tostring(value))
	end
	
	return table.concat(output, ", ")
end

function export.show(frame)
	local t = sortedTable(sort)
	
	t[1] = "number one"
	t.a = "ayy"
	t.h = "aitch"
	t["1"] = "one"
	t.A = "Ayy"
	t.z = "zee"
	t["ὦ"] = "O"
	t["Ж"] = "Zh"
	t["b"] = "bee"
	t["B"] = "Bee"
	
	local print = printTable(t) .. "\n\n" .. printTable{ a = "ayy", A = "Ayy", z = "zee", ["1"] = "one" }
	
	--[[
	mw.logObject(getmetatable(t))
	
	for key, value in pairs(t) do
		-- mw.log(key .. ": " .. value)
		t[key] = nil
	end
	
	mw.logObject(getmetatable(t))
	]]
	
	return print
end

return export