sctools>Alistair3149 |
|
Line 1: |
Line 1: |
| -- <nowiki> awawa
| |
| local libraryUtil = require('libraryUtil')
| |
| local checkType = libraryUtil.checkType
| |
| local checkTypeMulti = libraryUtil.checkTypeMulti
| |
| local arr = {}
| |
|
| |
|
| setmetatable(arr, {
| |
| __call = function (_, array)
| |
| return arr.new(array)
| |
| end
| |
| })
| |
|
| |
| function arr.__index(t, k)
| |
| if type(k) == 'table' then
| |
| local res = arr.new()
| |
| for i = 1, #t do
| |
| res[i] = t[k[i]]
| |
| end
| |
| return res
| |
| else
| |
| return arr[k]
| |
| end
| |
| end
| |
|
| |
| function arr.__tostring(array)
| |
| local dumpObject = require('Module:Logger').dumpObject
| |
| setmetatable(array, nil)
| |
| local str = dumpObject(array, {clean=true, collapseLimit=100})
| |
| setmetatable(array, arr)
| |
| return str
| |
| end
| |
|
| |
| function arr.__concat(lhs, rhs)
| |
| if type(lhs) == 'table' and type(rhs) == 'table' then
| |
| local res = setmetatable({}, getmetatable(lhs) or getmetatable(rhs))
| |
| for i = 1, #lhs do
| |
| res[i] = lhs[i]
| |
| end
| |
| local l = #lhs
| |
| for i = 1, #rhs do
| |
| res[i + l] = rhs[i]
| |
| end
| |
| return res
| |
| else
| |
| return tostring(lhs) .. tostring(rhs)
| |
| end
| |
| end
| |
|
| |
| function arr.__unm(array)
| |
| return arr.map(array, function(x) return -x end)
| |
| end
| |
|
| |
| local function mathTemplate(lhs, rhs, funName, fun)
| |
| checkTypeMulti('Module:Array.' .. funName, 1, lhs, {'number', 'table'})
| |
| checkTypeMulti('Module:Array.' .. funName, 2, rhs, {'number', 'table'})
| |
| local res = setmetatable({}, getmetatable(lhs) or getmetatable(rhs))
| |
|
| |
| if type(lhs) == 'number' then
| |
| for i = 1, #rhs do
| |
| res[i] = fun(lhs, rhs[i])
| |
| end
| |
| elseif type(rhs) == 'number' then
| |
| for i = 1, #lhs do
| |
| res[i] = fun(lhs[i], rhs)
| |
| end
| |
| else
| |
| assert(#lhs == #rhs, string.format('Tables are not equal length (lhs=%d, rhs=%d)', #lhs, #rhs))
| |
| for i = 1, #lhs do
| |
| res[i] = fun(lhs[i], rhs[i])
| |
| end
| |
| end
| |
|
| |
| return res
| |
| end
| |
|
| |
| function arr.__add(lhs, rhs)
| |
| return mathTemplate(lhs, rhs, '__add', function(x, y) return x + y end)
| |
| end
| |
|
| |
| function arr.__sub(lhs, rhs)
| |
| return mathTemplate(lhs, rhs, '__sub', function(x, y) return x - y end)
| |
| end
| |
|
| |
| function arr.__mul(lhs, rhs)
| |
| return mathTemplate(lhs, rhs, '__mul', function(x, y) return x * y end)
| |
| end
| |
|
| |
| function arr.__div(lhs, rhs)
| |
| return mathTemplate(lhs, rhs, '__div', function(x, y) return x / y end)
| |
| end
| |
|
| |
| function arr.__pow(lhs, rhs)
| |
| return mathTemplate(lhs, rhs, '__pow', function(x, y) return x ^ y end)
| |
| end
| |
|
| |
| function arr.__lt(lhs, rhs)
| |
| for i = 1, math.min(#lhs, #rhs) do
| |
| if lhs[i] >= rhs[i] then
| |
| return false
| |
| end
| |
| end
| |
| return true
| |
| end
| |
|
| |
| function arr.__le(lhs, rhs)
| |
| for i = 1, math.min(#lhs, #rhs) do
| |
| if lhs[i] > rhs[i] then
| |
| return false
| |
| end
| |
| end
| |
| return true
| |
| end
| |
|
| |
| function arr.__eq(lhs, rhs)
| |
| if #lhs ~= #rhs then
| |
| return false
| |
| end
| |
| for i = 1, #lhs do
| |
| if lhs[i] ~= rhs[i] then
| |
| return false
| |
| end
| |
| end
| |
| return true
| |
| end
| |
|
| |
| function arr.all(array, fn)
| |
| checkType('Module:Array.all', 1, array, 'table')
| |
| if fn == nil then fn = function(item) return item end end
| |
| if type(fn) ~= 'function' then
| |
| local val = fn
| |
| fn = function(item) return item == val end
| |
| end
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if not fn(array[i], i) then
| |
| return false
| |
| end
| |
| i = i + 1
| |
| end
| |
| return true
| |
| end
| |
|
| |
| function arr.any(array, fn)
| |
| checkType('Module:Array.any', 1, array, 'table')
| |
| if fn == nil then fn = function(item) return item end end
| |
| if type(fn) ~= 'function' then
| |
| local val = fn
| |
| fn = function(item) return item == val end
| |
| end
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if fn(array[i], i) then
| |
| return true
| |
| end
| |
| i = i + 1
| |
| end
| |
| return false
| |
| end
| |
|
| |
| function arr.clean(array)
| |
| checkType('Module:Array.clean', 1, array, 'table')
| |
| for i = 1, #array do
| |
| if type(array[i]) == 'table' then
| |
| arr.clean(array[i])
| |
| end
| |
| end
| |
| setmetatable(array, nil)
| |
| return array
| |
| end
| |
|
| |
| function arr.contains(array, elem, useElemTableContent)
| |
| checkType('Module:Array.contains', 1, array, 'table')
| |
| if type(elem) == 'table' and useElemTableContent ~= false then
| |
| local elemMap = {}
| |
| local isFound = {}
| |
| arr.each(elem, function(x, i) elemMap[x] = i; isFound[i] = false end)
| |
| for i = 1, #array do
| |
| local j = elemMap[array[i]]
| |
| if j then
| |
| isFound[j] = true
| |
| end
| |
| end
| |
| return arr.all(isFound, true)
| |
| else
| |
| return arr.any(array, function(item) return item == elem end)
| |
| end
| |
| end
| |
|
| |
| function arr.count(array, fn)
| |
| checkType('Module:Array.count', 1, array, 'table')
| |
| if fn == nil then fn = function(item) return item end end
| |
| if type(fn) ~= 'function' then
| |
| local val = fn
| |
| fn = function(item) return item == val end
| |
| end
| |
| local count = 0
| |
| for i = 1, #array do
| |
| if fn(array[i]) then
| |
| count = count + 1
| |
| end
| |
| end
| |
| return count
| |
| end
| |
|
| |
| function arr.diff(array, order)
| |
| checkType('Module:Array.diff', 1, array, 'table')
| |
| checkType('Module:Array.diff', 2, order, 'number', true)
| |
| local res = setmetatable({}, getmetatable(array))
| |
| for i = 1, #array - 1 do
| |
| res[i] = array[i+1] - array[i]
| |
| end
| |
| if order and order > 1 then
| |
| return arr.diff(res, order - 1)
| |
| end
| |
| return res
| |
| end
| |
|
| |
| function arr.each(array, fn)
| |
| checkType('Module:Array.each', 1, array, 'table')
| |
| checkType('Module:Array.each', 2, fn, 'function')
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| fn(array[i], i)
| |
| i = i + 1
| |
| end
| |
| end
| |
|
| |
| function arr.filter(array, fn)
| |
| checkType('Module:Array.filter', 1, array, 'table')
| |
| if fn == nil then fn = function(item) return item end end
| |
| if type(fn) ~= 'function' then
| |
| local val = fn
| |
| fn = function(item) return item == val end
| |
| end
| |
| local r = setmetatable({}, getmetatable(array))
| |
| local len = 0
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if fn(array[i], i) then
| |
| len = len + 1
| |
| r[len] = array[i]
| |
| end
| |
| i = i + 1
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.find(array, fn, default)
| |
| checkType('Module:Array.find', 1, array, 'table')
| |
| checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'})
| |
| if type(fn) ~= 'function' then
| |
| local val = fn
| |
| fn = function(item) return item == val end
| |
| end
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if fn(array[i], i) then
| |
| return array[i], i
| |
| end
| |
| i = i + 1
| |
| end
| |
| return default
| |
| end
| |
|
| |
| function arr.find_index(array, fn, default)
| |
| checkType('Module:Array.find_index', 1, array, 'table')
| |
| checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'})
| |
| if type(fn) ~= 'function' then
| |
| local val = fn
| |
| fn = function(item) return item == val end
| |
| end
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if fn(array[i], i) then
| |
| return i
| |
| end
| |
| i = i + 1
| |
| end
| |
| return default
| |
| end
| |
|
| |
| function arr.newIncrementor(start, step)
| |
| checkType('Module:Array.newIncrementor', 1, start, 'number', true)
| |
| checkType('Module:Array.newIncrementor', 2, step, 'number', true)
| |
| step = step or 1
| |
| local n = (start or 1) - step
| |
| local obj = {}
| |
| return setmetatable(obj, {
| |
| __call = function() n = n + step return n end,
| |
| __tostring = function() return n end,
| |
| __index = function() return n end,
| |
| __newindex = function(self, k, v)
| |
| if k == 'step' and type(v) == 'number' then
| |
| step = v
| |
| elseif type(v) == 'number' then
| |
| n = v
| |
| end
| |
| end,
| |
| __concat = function(x, y) return tostring(x) .. tostring(y) end
| |
| })
| |
| end
| |
|
| |
| function arr.int(array, start, stop)
| |
| checkType('Module:Array.int', 1, array, 'table')
| |
| checkType('Module:Array.int', 2, start, 'number', true)
| |
| checkType('Module:Array.int', 3, stop, 'number', true)
| |
| local res = setmetatable({}, getmetatable(array))
| |
| start = start or 1
| |
| stop = stop or #array
| |
| res[1] = array[start]
| |
| for i = 1, stop - start do
| |
| res[i+1] = res[i] + array[start + i]
| |
| end
| |
| return res
| |
| end
| |
|
| |
| function arr.intersect(array1, array2)
| |
| checkType('Module:Array.intersect', 1, array1, 'table')
| |
| checkType('Module:Array.intersect', 2, array2, 'table')
| |
| local array2Elements = {}
| |
| local res = setmetatable({}, getmetatable(array1) or getmetatable(array2))
| |
| local len = 0
| |
| arr.each(array2, function(item) array2Elements[item] = true end)
| |
| arr.each(array1, function(item)
| |
| if array2Elements[item] then
| |
| len = len + 1
| |
| res[len] = item
| |
| end
| |
| end)
| |
| return res
| |
| end
| |
|
| |
| function arr.intersects(array1, array2)
| |
| checkType('Module:Array.intersects', 1, array1, 'table')
| |
| checkType('Module:Array.intersects', 2, array2, 'table')
| |
| local small = {}
| |
| local large
| |
| if #array1 <= #array2 then
| |
| arr.each(array1, function(item) small[item] = true end)
| |
| large = array2
| |
| else
| |
| arr.each(array2, function(item) small[item] = true end)
| |
| large = array1
| |
| end
| |
| return arr.any(large, function(item) return small[item] end)
| |
| end
| |
|
| |
| function arr.insert(array, val, index, unpackVal)
| |
| checkType('Module:Array.insert', 1, array, 'table')
| |
| checkType('Module:Array.insert', 3, index, 'number', true)
| |
| checkType('Module:Array.insert', 4, unpackVal, 'boolean', true)
| |
| local len = #array
| |
| index = index or (len + 1)
| |
|
| |
| if type(val) == 'table' and unpackVal ~= false then
| |
| local len2 = #val
| |
| for i = 0, len - index do
| |
| array[len + len2 - i] = array[len - i]
| |
| end
| |
| for i = 0, len2 - 1 do
| |
| array[index + i] = val[i + 1]
| |
| end
| |
| else
| |
| table.insert(array, index, val)
| |
| end
| |
|
| |
| return array
| |
| end
| |
|
| |
| function arr.map(array, fn)
| |
| checkType('Module:Array.map', 1, array, 'table')
| |
| checkType('Module:Array.map', 2, fn, 'function')
| |
| local len = 0
| |
| local r = setmetatable({}, getmetatable(array))
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| local tmp = fn(array[i], i)
| |
| if tmp ~= nil then
| |
| len = len + 1
| |
| r[len] = tmp
| |
| end
| |
| i = i + 1
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.max_by(array, fn)
| |
| checkType('Module:Array.max_by', 1, array, 'table')
| |
| checkType('Module:Array.max_by', 2, fn, 'function')
| |
| return unpack(arr.reduce(array, function(new, old, i)
| |
| local y = fn(new)
| |
| return y > old[2] and {new, y, i} or old
| |
| end, {nil, -math.huge}))
| |
| end
| |
|
| |
| function arr.max(array)
| |
| checkType('Module:Array.max', 1, array, 'table')
| |
| local val, _, i = arr.max_by(array, function(x) return x end)
| |
| return val, i
| |
| end
| |
|
| |
| function arr.min(array)
| |
| checkType('Module:Array.min', 1, array, 'table')
| |
| local val, _, i = arr.max_by(array, function(x) return -x end)
| |
| return val, i
| |
| end
| |
|
| |
| function arr.new(array)
| |
| array = array or {}
| |
| for _, v in pairs(array) do
| |
| if type(v) == 'table' then
| |
| arr.new(v)
| |
| end
| |
| end
| |
|
| |
| if getmetatable(array) == nil then
| |
| setmetatable(array, arr)
| |
| end
| |
|
| |
| return array
| |
| end
| |
|
| |
| function arr.range(start, stop, step)
| |
| checkType('Module:Array.range', 1, start, 'number')
| |
| checkType('Module:Array.range', 2, stop, 'number', true)
| |
| checkType('Module:Array.range', 3, step, 'number', true)
| |
| local array = setmetatable({}, arr)
| |
| local len = 0
| |
| if not stop then
| |
| stop = start
| |
| start = 1
| |
| end
| |
| for i = start, stop, step or 1 do
| |
| len = len + 1
| |
| array[len] = i
| |
| end
| |
| return array
| |
| end
| |
|
| |
| function arr.reduce(array, fn, accumulator)
| |
| checkType('Module:Array.reduce', 1, array, 'table')
| |
| checkType('Module:Array.reduce', 2, fn, 'function')
| |
| local acc = accumulator
| |
| local i = 1
| |
| if acc == nil then
| |
| acc = array[1]
| |
| i = 2
| |
| end
| |
| while array[i] ~= nil do
| |
| acc = fn(array[i], acc, i)
| |
| i = i + 1
| |
| end
| |
| return acc
| |
| end
| |
|
| |
| function arr.reject(array, fn)
| |
| checkType('Module:Array.reject', 1, array, 'table')
| |
| checkTypeMulti('Module:Array.reject', 2, fn, {'function', 'table', 'number', 'boolean'})
| |
| if fn == nil then fn = function(item) return item end end
| |
| if type(fn) ~= 'function' and type(fn) ~= 'table' then
| |
| fn = {fn}
| |
| end
| |
| local r = setmetatable({}, getmetatable(array))
| |
| local len = 0
| |
| if type(fn) == 'function' then
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if not fn(array[i], i) then
| |
| len = len + 1
| |
| r[len] = array[i]
| |
| end
| |
| i = i + 1
| |
| end
| |
| else
| |
| local rejectMap = {}
| |
| arr.each(fn, function(item) rejectMap[item] = true end)
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if not rejectMap[array[i]] then
| |
| len = len + 1
| |
| r[len] = array[i]
| |
| end
| |
| i = i + 1
| |
| end
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.rep(val, n)
| |
| checkType('Module:Array.rep', 2, n, 'number')
| |
| local r = setmetatable({}, arr)
| |
| for i = 1, n do
| |
| r[i] = val
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.scan(array, fn, accumulator)
| |
| checkType('Module:Array.scan', 1, array, 'table')
| |
| checkType('Module:Array.scan', 2, fn, 'function')
| |
| local acc = accumulator
| |
| local r = setmetatable({}, getmetatable(array))
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| if i == 1 and not accumulator then
| |
| acc = array[i]
| |
| else
| |
| acc = fn(array[i], acc)
| |
| end
| |
| r[i] = acc
| |
| i = i + 1
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.slice(array, start, finish)
| |
| checkType('Module:Array.slice', 1, array, 'table')
| |
| checkType('Module:Array.slice', 2, start, 'number', true)
| |
| checkType('Module:Array.slice', 3, finish, 'number', true)
| |
| start = start or 1
| |
| finish = finish or #array
| |
| if start < 0 and finish == nil then
| |
| finish = #array + start
| |
| start = 1
| |
| elseif start < 0 then
| |
| start = #array + start
| |
| end
| |
| if finish < 0 then
| |
| finish = #array + finish
| |
| end
| |
| local r = setmetatable({}, getmetatable(array))
| |
| local len = 0
| |
| for i = start, finish do
| |
| len = len + 1
| |
| r[len] = array[i]
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.split(array, count)
| |
| checkType('Module:Array.split', 1, array, 'table')
| |
| checkType('Module:Array.split', 2, count, 'number')
| |
| local x = setmetatable({}, getmetatable(array))
| |
| local y = setmetatable({}, getmetatable(array))
| |
| for i = 1, #array do
| |
| table.insert(i <= count and x or y, array[i])
| |
| end
| |
| return x, y
| |
| end
| |
|
| |
| function arr.sum(array)
| |
| checkType('Module:Array.sum', 1, array, 'table')
| |
| local res = 0
| |
| for i = 1, #array do
| |
| res = res + array[i]
| |
| end
| |
| return res
| |
| end
| |
|
| |
| function arr.take(array, count, offset)
| |
| checkType('Module:Array.take', 1, array, 'table')
| |
| checkType('Module:Array.take', 2, count, 'number')
| |
| checkType('Module:Array.take', 3, offset, 'number', true)
| |
| local x = setmetatable({}, getmetatable(array))
| |
| for i = offset or 1, #array do
| |
| if i <= count then
| |
| table.insert(x, array[i])
| |
| end
| |
| end
| |
| return x
| |
| end
| |
|
| |
| function arr.take_every(array, n, offset)
| |
| checkType('Module:Array.take_every', 1, array, 'table')
| |
| checkType('Module:Array.take_every', 2, n, 'number')
| |
| checkType('Module:Array.take_every', 3, offset, 'number', true)
| |
| local r = setmetatable({}, getmetatable(array))
| |
| local len = 0
| |
| local i = offset or 1
| |
| while array[i] ~= nil do
| |
| len = len + 1
| |
| r[len] = array[i]
| |
| i = i + n
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.unique(array, fn)
| |
| checkType('Module:Array.unique', 1, array, 'table')
| |
| checkType('Module:Array.unique', 2, fn, 'function', true)
| |
| fn = fn or function(item) return item end
| |
| local r = setmetatable({}, getmetatable(array))
| |
| local len = 0
| |
| local hash = {}
| |
| local i = 1
| |
| while array[i] ~= nil do
| |
| local id = fn(array[i])
| |
| if not hash[id] then
| |
| len = len + 1
| |
| r[len] = array[i]
| |
| hash[id] = true
| |
| end
| |
| i = i + 1
| |
| end
| |
| return r
| |
| end
| |
|
| |
| function arr.update(array, indexes, values)
| |
| checkType('Module:Array.update', 1, array, 'table')
| |
| checkTypeMulti('Module:Array.update', 2, indexes, {'table', 'number'})
| |
| if type(indexes) == 'number' then
| |
| indexes = {indexes}
| |
| end
| |
| if type(values) == 'table' then
| |
| assert(#indexes == #values, 'Values array must be of equal length as index array')
| |
| for i = 1, #indexes do
| |
| array[indexes[i]] = values[i]
| |
| end
| |
| else
| |
| for i = 1, #indexes do
| |
| array[indexes[i]] = values
| |
| end
| |
| end
| |
| return array
| |
| end
| |
|
| |
| function arr.zip(...)
| |
| local arrays = { ... }
| |
| checkType('Module:Array.zip', 1, arrays[1], 'table')
| |
| local r = setmetatable({}, getmetatable(arrays[1]))
| |
| local _, longest = arr.max_by(arrays, function(array) return #array end)
| |
| for i = 1, longest do
| |
| local q = {}
| |
| for j = 1, #arrays do
| |
| table.insert(q, arrays[j][i])
| |
| end
| |
| table.insert(r, q)
| |
| end
| |
| return r
| |
| end
| |
|
| |
| return arr
| |
| -- </nowiki>
| |