Module:UtilsTable

local p = {}

local lang = mw.getLanguage('en')

p.print = require("Module:UtilsTable/Inspect")

-- Shallow clone of table with only string keys function p.cloneRecord(tbl) local result = {} for k, v in pairs(tbl) do		if type(k) == "string" then result[k] = v		end end return result end

function p.keyOf(tbl, val) for k, v in pairs(tbl) do		if v == val then return k		end end return nil end

function p.keys(tbl) local keyset = {} for k in pairs(tbl) do     keyset[#keyset + 1] = k   end return keyset end

function p.hash(tbl) local hash = {} for k, v in pairs(tbl) do		hash[v] = k	end return hash end

function p.isArray(tbl) if type(tbl) ~= "table" then return false end return #tbl == p.size(tbl) end

function p.merge(...) local result = {} for _, tbl in ipairs(arg) do		for k, v in pairs(tbl) do			result[k] = v		end end return result end

-- table.remove for non-integer key function p.remove(tbl, key) local output = tbl[key] tbl[key] = nil return output end

function p.shallowClone(tbl) -- mostly to be able to use # operator on something from mw.loadData local tbl2 = {} for k, v in pairs(tbl) do		tbl2[k] = v	end return tbl2 end

function p.size(tbl) return #p.keys(tbl) end

-- See also ivalues function p.values(tbl) local valueset = {} for _, v in pairs(tbl) do     table.insert(valueset, v)   end return valueset end

-- See also p.values function p.ivalues(tbl) local valueset = {} for _, v in ipairs(tbl) do     table.insert(valueset, v)   end return valueset end

--	"Array" functions (using the `ipairs` iterator, mostly) -- function p.alphabetize(tbl) local hash = {} local nocase = {} for i, v in ipairs(tbl) do		nocase[i] = lang:caseFold(v) hash[nocase[i]] = v	end table.sort(nocase) for i, v in ipairs(nocase) do		tbl[i] = hash[v] end return tbl end

function p.crop(tbl, max) for k, _ in ipairs(tbl) do		if k > max then tbl[k] = nil end end end

function p.filter(predicate, tbl) local predicateFn = predicate if type(predicate) == "string" then predicateFn = function(val) return val[predicate] end elseif not type(predicate) == "function" then error("Argument #1 to  must be of type   or  ") end local results = {} for _, val in ipairs(tbl) do		if predicateFn(val) then table.insert(results, val) end end return results end

function p.flatten(tbl) local result = {} for _, v in ipairs(tbl) do		if p.isArray(v) then result = p.mergeArrays(result, p.flatten(v)) else table.insert(result, v)		end end return result end

function p.flatMap(mappingFunction, tbl) return p.flatten(p.map(mappingFunction, tbl)) end

function p.groupBy(key, tbl) if not key then return tbl end local result = {} for _, v in ipairs(tbl) do		local groupingKey = v[key] or "" local group = result[groupingKey] or {} table.insert(group, v)		result[groupingKey] = group end return result end

function p.map(iteratee, tbl) local mappingFunction = iteratee if type(iteratee) == "string" then mappingFunction = function(val) return val[iteratee] end end local tbl2 = {} for k, v in ipairs(tbl) do		tbl2[k] = mappingFunction(v) end return tbl2 end

-- @param Returns a new array grouping together the values of the arrays given. Order is preserved. function p.mergeArrays(...) local merged = {} for _, tbl in ipairs(arg) do		for _, v in ipairs(tbl) do			merged[#merged+1] = v		end end return merged end

-- prints the table as a comma-separated list with and function p.printList(tbl) if #tbl == 1 then return tbl[1] elseif #tbl == 2 then return table.concat(tbl, ' and ') else last = table.remove(tbl, #tbl) list = table.concat(tbl, ', ') return list .. ', and ' .. (last or '') end end

-- Returns the list with duplicate values removed. function p.removeDuplicates(list) local hash = {} local result = {}

for key, value in pairs(list) do		if (not hash[value]) then result[#result+1] = value hash[value] = true end end return result end

function p.removeFalseEntries(tbl, max) if not max then max = #tbl end local j = 0 for i = 1, max do		if tbl[i] then j = j + 1 tbl[j] = tbl[i] end end for i = j+1, max do		tbl[i] = nil end return tbl end

function p.replaceFalseEntries(tbl, max, default) default = default or '' for i = 1, max do		if not tbl[i] then tbl[i] = default end end return tbl end

-- returns a copy of tbl with the elements in opposite order (not a deep copy) function p.reverse(tbl) local tbl2 = {} local len = #tbl for i = len, 1, -1 do		tbl2[len - i + 1] = tbl[i] end return tbl2 end

function p.slice(tbl, s, e)	local tbl2 = {} for k = s, e do		tbl2[#tbl2+1] = tbl[k] end return tbl2 end

-- sorts tblToSort to be in the same order as the elements appear in lookup function p.sortByKeyOrder(tblToSort, values) local lookup = p.hash(values) table.sort(tblToSort, function (a,b)			return (lookup[a] or 0) < (lookup[b] or 0)		end	) return end

function p.sortUnique(tbl) table.sort(tbl) local tbl2 = {} local i = 0 for k, v in ipairs(tbl) do		if v ~= tbl2[i] then i = i + 1 tbl2[i] = v		end end return tbl2 end

function p.takeWhile(property, tbl) local results = {} local i = 1 while tbl[i] and tbl[i][property] do		table.insert(results, tbl[i]) i = i + 1 end return results end

-- From https://github.com/lua-stdlib/functional -- See https://lua-stdlib.github.io/lua-stdlib/modules/std.functional.html#zip function p.zip(tbl) local result = {} for outerk, innerTbl in ipairs(tbl) do     for k, v in ipairs(innerTbl) do         result[k] = result[k] or {} result[k][outerk] = v     end end return result end

return p