Module:Array: Difference between revisionsGive feedback
osrsw>Shoyrukon m Protected "Module:Enum" ([Edit=Only allow autoconfirmed users] (indefinite) [Move=Only allow autoconfirmed users] (indefinite)) |
osrsw>CephHunter Sync with rsw |
||
| Line 3: | Line 3: | ||
local checkType = libraryUtil.checkType | local checkType = libraryUtil.checkType | ||
local checkTypeMulti = libraryUtil.checkTypeMulti | local checkTypeMulti = libraryUtil.checkTypeMulti | ||
local | local arr = {} | ||
function | setmetatable(arr, { | ||
__call = function (_, array) | |||
return arr.new(array) | |||
checkType('Module:Enum.all', | end | ||
if | }) | ||
fn = fn | |||
function arr.__index(t, k) | |||
if not fn( | 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 = mw.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:Enum.' .. funName, 1, lhs, {'number', 'table'}) | |||
checkTypeMulti('Module:Enum.' .. 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:Enum.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 | return false | ||
end | end | ||
i = i + 1 | |||
end | end | ||
return true | return true | ||
end | end | ||
function | function arr.any(array, fn) | ||
checkType('Module:Enum.any', 1, | checkType('Module:Enum.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 | |||
if fn( | local i = 1 | ||
while array[i] ~= nil do | |||
if fn(array[i], i) then | |||
return true | return true | ||
end | end | ||
i = i + 1 | |||
end | end | ||
return false | return false | ||
end | end | ||
function | function arr.clean(array) | ||
checkType('Module:Enum. | checkType('Module:Enum.clean', 1, array, 'table') | ||
checkType('Module:Enum.contains', | for i = 1, #array do | ||
if | if type(array[i]) == 'table' then | ||
return | arr.clean(array[i]) | ||
end | |||
end | |||
setmetatable(array, nil) | |||
return array | |||
end | |||
function arr.contains(array, elem, useElemTableContent) | |||
checkType('Module:Enum.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:Enum.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 | end | ||
function | function arr.diff(array, order) | ||
checkType('Module:Enum.each', 1, | checkType('Module:Enum.diff', 1, array, 'table') | ||
checkType('Module:Enum.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:Enum.each', 1, array, 'table') | |||
checkType('Module:Enum.each', 2, fn, 'function') | checkType('Module:Enum.each', 2, fn, 'function') | ||
local i = 1 | |||
while array[i] ~= nil do | |||
fn(array[i], i) | |||
fn( | i = i + 1 | ||
end | end | ||
end | end | ||
function | function arr.filter(array, fn) | ||
checkType('Module:Enum.filter', 1, | checkType('Module:Enum.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 | |||
local r = {} | end | ||
local r = setmetatable({}, getmetatable(array)) | |||
if fn( | 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 | end | ||
i = i + 1 | |||
end | end | ||
return r | return r | ||
end | end | ||
function | function arr.find(array, fn, default) | ||
checkType('Module:Enum.find', 1, | checkType('Module:Enum.find', 1, array, 'table') | ||
checkTypeMulti('Module:Enum.find_index', 2, fn, {'function', 'table', 'number', 'boolean'}) | |||
if type(fn) ~= 'function' then | |||
if | local val = fn | ||
fn = function(item) return item == val end | |||
if fn( | end | ||
return | local i = 1 | ||
while array[i] ~= nil do | |||
if fn(array[i], i) then | |||
return array[i], i | |||
end | end | ||
i = i + 1 | |||
end | end | ||
return default | return default | ||
end | end | ||
function | function arr.find_index(array, fn, default) | ||
checkType('Module:Enum.find_index', 1, | checkType('Module:Enum.find_index', 1, array, 'table') | ||
checkTypeMulti('Module:Enum.find_index', 2, fn, {'function', 'table', 'number', 'boolean'}) | |||
if type(fn) ~= 'function' then | |||
if | local val = fn | ||
fn = function(item) return item == val end | |||
if fn( | end | ||
return | local i = 1 | ||
while array[i] ~= nil do | |||
if fn(array[i], i) then | |||
return i | |||
end | end | ||
i = i + 1 | |||
end | end | ||
return default | return default | ||
end | end | ||
function | function arr.newIncrementor(start, step) | ||
checkType('Module:Enum.newIncrementor', 1, start, 'number', true) | checkType('Module:Enum.newIncrementor', 1, start, 'number', true) | ||
checkType('Module:Enum.newIncrementor', 2, step, 'number', true) | checkType('Module:Enum.newIncrementor', 2, step, 'number', true) | ||
| Line 112: | Line 301: | ||
end | end | ||
function | function arr.int(array, start, stop) | ||
checkType('Module:Enum. | checkType('Module:Enum.int', 1, array, 'table') | ||
checkType('Module:Enum. | checkType('Module:Enum.int', 2, start, 'number', true) | ||
checkType('Module:Enum. | checkType('Module:Enum.int', 3, stop, 'number', true) | ||
local res = setmetatable({}, getmetatable(array)) | |||
local | start = start or 1 | ||
local res = {} | stop = stop or #array | ||
res[1] = array[start] | |||
for i = 1, stop - start do | |||
if | res[i+1] = res[i] + array[start + i] | ||
end | |||
return res | |||
end | |||
function arr.intersect(array1, array2) | |||
checkType('Module:Enum.intersect', 1, array1, 'table') | |||
checkType('Module:Enum.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 | ||
end) | end) | ||
| Line 128: | Line 331: | ||
end | end | ||
function | function arr.intersects(array1, array2) | ||
checkType('Module:Enum.intersects', 1, | checkType('Module:Enum.intersects', 1, array1, 'table') | ||
checkType('Module:Enum.intersects', 2, | checkType('Module:Enum.intersects', 2, array2, 'table') | ||
local small = {} | |||
if | 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 | end | ||
function | function arr.insert(array, val, index, unpackVal) | ||
checkType('Module:Enum.insert', 1, | checkType('Module:Enum.insert', 1, array, 'table') | ||
checkType('Module:Enum.insert', 3, index, 'number', true) | checkType('Module:Enum.insert', 3, index, 'number', true) | ||
checkType('Module:Enum.insert', 4, | checkType('Module:Enum.insert', 4, unpackVal, 'boolean', true) | ||
local len = #array | |||
local | index = index or (len + 1) | ||
index = index or ( | |||
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 | end | ||
else | |||
table.insert(array, index, val) | |||
end | end | ||
return | return array | ||
end | end | ||
function | function arr.map(array, fn) | ||
checkType('Module:Enum.map', 1, | checkType('Module:Enum.map', 1, array, 'table') | ||
checkType('Module:Enum.map', 2, fn, 'function') | checkType('Module:Enum.map', 2, fn, 'function') | ||
local len = 0 | |||
local r = setmetatable({}, getmetatable(array)) | |||
local | local i = 1 | ||
while array[i] ~= nil do | |||
local | local tmp = fn(array[i], i) | ||
if tmp ~= nil then | |||
len = len + 1 | |||
r[len] = tmp | |||
end | |||
i = i + 1 | |||
end | end | ||
return r | return r | ||
end | end | ||
function | function arr.max_by(array, fn) | ||
checkType('Module:Enum.max_by', 1, | checkType('Module:Enum.max_by', 1, array, 'table') | ||
checkType('Module:Enum.max_by', 2, fn, 'function') | checkType('Module:Enum.max_by', 2, fn, 'function') | ||
return unpack(arr.reduce(array, function(new, old, i) | |||
return unpack( | |||
local y = fn(new) | local y = fn(new) | ||
return y > old[2] and {new, y} or old | return y > old[2] and {new, y, i} or old | ||
end, { | end, {nil, -math.huge})) | ||
end | |||
function arr.max(array) | |||
checkType('Module:Enum.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:Enum.min', 1, array, 'table') | |||
local val, _, i = arr.max_by(array, function(x) return -x end) | |||
return val, i | |||
end | end | ||
function | 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:Enum.range', 1, start, 'number') | checkType('Module:Enum.range', 1, start, 'number') | ||
checkType('Module:Enum.range', 2, stop, 'number', true) | checkType('Module:Enum.range', 2, stop, 'number', true) | ||
checkType('Module:Enum.range', 3, step, 'number', true) | checkType('Module:Enum.range', 3, step, 'number', true) | ||
local array = {} | local array = setmetatable({}, arr) | ||
local len = 0 | |||
if not stop then | if not stop then | ||
stop = start | stop = start | ||
start = 1 | start = 1 | ||
end | end | ||
for i = start, stop, step or 1 do | for i = start, stop, step or 1 do | ||
array[ | len = len + 1 | ||
array[len] = i | |||
end | end | ||
return array | return array | ||
end | end | ||
function | function arr.reduce(array, fn, accumulator) | ||
checkType('Module:Enum.reduce', 1, | checkType('Module:Enum.reduce', 1, array, 'table') | ||
checkType('Module:Enum.reduce', 2, fn, 'function') | checkType('Module:Enum.reduce', 2, fn, 'function') | ||
local acc = accumulator | 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 | end | ||
return acc | return acc | ||
end | end | ||
function | function arr.reject(array, fn) | ||
checkType('Module:Enum.reject', 1, | checkType('Module:Enum.reject', 1, array, 'table') | ||
checkTypeMulti('Module:Enum.reject', 2, fn, {'function', 'table', ' | checkTypeMulti('Module:Enum.reject', 2, fn, {'function', 'table', 'number', 'boolean'}) | ||
if fn == nil then fn = function(item) return item end end | |||
if | if type(fn) ~= 'function' and type(fn) ~= 'table' then | ||
fn = | fn = {fn} | ||
local r = {} | end | ||
local r = setmetatable({}, getmetatable(array)) | |||
local len = 0 | |||
if type(fn) == 'function' then | if type(fn) == 'function' then | ||
local i = 1 | |||
if not fn( | while array[i] ~= nil do | ||
if not fn(array[i], i) then | |||
len = len + 1 | |||
r[len] = array[i] | |||
end | end | ||
i = i + 1 | |||
end | end | ||
else | else | ||
local rejectMap = {} | 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 | |||
if not rejectMap[ | len = len + 1 | ||
r[len] = array[i] | |||
end | end | ||
i = i + 1 | |||
end | end | ||
end | end | ||
| Line 244: | Line 487: | ||
end | end | ||
function | function arr.rep(val, n) | ||
checkType('Module:Enum.scan', 1, | checkType('Module:Enum.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:Enum.scan', 1, array, 'table') | |||
checkType('Module:Enum.scan', 2, fn, 'function') | checkType('Module:Enum.scan', 2, fn, 'function') | ||
local acc = accumulator | local acc = accumulator | ||
local r = {} | local r = setmetatable({}, getmetatable(array)) | ||
local i = 1 | |||
if | while array[i] ~= nil do | ||
acc = | if i == 1 and not accumulator then | ||
acc = array[i] | |||
else | else | ||
acc = fn( | acc = fn(array[i], acc) | ||
end | end | ||
r[i] = acc | |||
i = i + 1 | |||
end | end | ||
return r | return r | ||
end | end | ||
function | function arr.slice(array, start, finish) | ||
checkType('Module:Enum.slice', 1, | checkType('Module:Enum.slice', 1, array, 'table') | ||
checkType('Module:Enum.slice', 2, start, 'number', true) | checkType('Module:Enum.slice', 2, start, 'number', true) | ||
checkType('Module:Enum.slice', 3, finish, 'number', true) | checkType('Module:Enum.slice', 3, finish, 'number', true) | ||
start = start or 1 | start = start or 1 | ||
finish = finish or # | 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 | end | ||
return r | return r | ||
end | end | ||
function | function arr.split(array, count) | ||
checkType('Module:Enum.split', 1, | checkType('Module:Enum.split', 1, array, 'table') | ||
checkType('Module:Enum.split', 2, count, 'number') | checkType('Module:Enum.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]) | |||
local y = {} | |||
for i = 1, # | |||
table.insert( | |||
end | end | ||
return x, y | return x, y | ||
end | end | ||
function | function arr.sum(array) | ||
checkType('Module:Enum.sum', 1, | checkType('Module:Enum.sum', 1, array, 'table') | ||
local res = 0 | |||
for i = 1, #array do | |||
return | res = res + array[i] | ||
end | |||
return res | |||
end | end | ||
function | function arr.take(array, count, offset) | ||
checkType('Module:Enum.take', 1, | checkType('Module:Enum.take', 1, array, 'table') | ||
checkType('Module:Enum.take', 2, count, 'number') | checkType('Module:Enum.take', 2, count, 'number') | ||
checkType('Module:Enum.take', 3, | checkType('Module:Enum.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 | return x | ||
end | end | ||
function | function arr.take_every(array, n, offset) | ||
checkType('Module:Enum.take_every', 1, | checkType('Module:Enum.take_every', 1, array, 'table') | ||
checkType('Module:Enum.take_every', 2, n, 'number') | checkType('Module:Enum.take_every', 2, n, 'number') | ||
checkType('Module:Enum.take_every', 3, | checkType('Module:Enum.take_every', 3, offset, 'number', true) | ||
local r = setmetatable({}, getmetatable(array)) | |||
local | local len = 0 | ||
local i = offset or 1 | |||
while array[i] ~= nil do | |||
len = len + 1 | |||
r[len] = array[i] | |||
i = i + n | |||
end | end | ||
return r | return r | ||
end | end | ||
function | function arr.unique(array, fn) | ||
checkType('Module:Enum.unique', 1, array, 'table') | |||
checkType('Module:Enum.unique', 1, | |||
checkType('Module:Enum.unique', 2, fn, 'function', true) | checkType('Module:Enum.unique', 2, fn, 'function', true) | ||
fn = fn or function(item) return item end | fn = fn or function(item) return item end | ||
local r = {} | local r = setmetatable({}, getmetatable(array)) | ||
local len = 0 | |||
local hash = {} | local hash = {} | ||
local i = 1 | |||
local id = fn( | while array[i] ~= nil do | ||
local id = fn(array[i]) | |||
if not hash[id] then | if not hash[id] then | ||
len = len + 1 | |||
r[len] = array[i] | |||
hash[id] = true | hash[id] = true | ||
end | end | ||
i = i + 1 | |||
end | end | ||
return r | return r | ||
end | end | ||
function | function arr.update(array, indexes, values) | ||
checkType('Module:Enum. | checkType('Module:Enum.update', 1, array, 'table') | ||
checkTypeMulti('Module:Enum.update', 2, indexes, {'table', 'number'}) | |||
if | if type(indexes) == 'number' then | ||
local r = {} | indexes = {indexes} | ||
local _, longest = | 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:Enum.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 | for i = 1, longest do | ||
local q = {} | local q = {} | ||
for j = 1, # | for j = 1, #arrays do | ||
table.insert(q, | table.insert(q, arrays[j][i]) | ||
end | end | ||
table.insert(r, q) | table.insert(r, q) | ||
| Line 378: | Line 640: | ||
end | end | ||
return | return arr | ||
-- </nowiki> | -- </nowiki> | ||