添加的内容 删除的内容
sctools>Alistair3149 无编辑摘要 |
小 (导入1个版本:Import Module Templates) |
||
第1行: | 第1行: | ||
-- <nowiki> awawa |
|||
-- Imported from: https://runescape.wiki/w/Module:Array |
|||
local libraryUtil = require('libraryUtil') |
local libraryUtil = require('libraryUtil') |
||
local checkType = libraryUtil.checkType |
local checkType = libraryUtil.checkType |
||
local checkTypeMulti = libraryUtil.checkTypeMulti |
local checkTypeMulti = libraryUtil.checkTypeMulti |
||
local arr = {} |
|||
setmetatable(arr, { |
|||
---@class Array |
|||
__call = function (_, array) |
|||
---@operator call(any[]): Array |
|||
return arr.new(array) |
|||
---@operator concat(any[]): Array |
|||
---@operator concat(number|string|function): string |
|||
---@operator unm: Array |
|||
---@operator add(number|number[]|Array): Array |
|||
---@operator sub(number|number[]|Array): Array |
|||
---@operator mul(number|number[]|Array): Array |
|||
---@operator div(number|number[]|Array): Array |
|||
---@operator pow(number|number[]|Array): Array |
|||
local Array = { |
|||
pop = table.remove |
|||
} |
|||
Array.__index = Array |
|||
setmetatable(Array, { |
|||
__index = table, |
|||
__call = function (_, arr) |
|||
return Array.new(arr) |
|||
end |
end |
||
}) |
}) |
||
function arr.__index(t, k) |
|||
if type(k) == 'table' then |
|||
-- -- local dumpObject = require('Module:Logger').dumpObject |
|||
local res = arr.new() |
|||
-- require 'log' |
|||
for i = 1, #t do |
|||
-- local dumpObject = dumpObject |
|||
res[i] = t[k[i]] |
|||
-- local mt = getmetatable(arr) |
|||
end |
|||
-- setmetatable(arr, nil) |
|||
return res |
|||
-- local str = dumpObject(arr, {clean=true, collapseLimit=100}) |
|||
else |
|||
-- setmetatable(arr, mt) |
|||
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 |
function arr.__concat(lhs, rhs) |
||
if type(lhs) == 'table' and type(rhs) == 'table' then |
if type(lhs) == 'table' and type(rhs) == 'table' then |
||
local res = {} |
local res = setmetatable({}, getmetatable(lhs) or getmetatable(rhs)) |
||
for i = 1, #lhs do |
for i = 1, #lhs do |
||
res[i] = lhs[i] |
res[i] = lhs[i] |
||
第48行: | 第41行: | ||
res[i + l] = rhs[i] |
res[i + l] = rhs[i] |
||
end |
end |
||
return res |
|||
return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) |
|||
else |
else |
||
return tostring(lhs) .. tostring(rhs) |
return tostring(lhs) .. tostring(rhs) |
||
第54行: | 第47行: | ||
end |
end |
||
function |
function arr.__unm(array) |
||
return |
return arr.map(array, function(x) return -x end) |
||
end |
end |
||
local function mathTemplate(lhs, rhs, funName, fun) |
|||
---@param lhs number|number[]|Array |
|||
---@param rhs number|number[]|Array |
|||
---@param funName string |
|||
---@param opName string |
|||
---@param fun fun(lhs: number, rhs: number): number |
|||
---@return Array |
|||
local function mathTemplate(lhs, rhs, funName, opName, fun) |
|||
checkTypeMulti('Module:Array.' .. funName, 1, lhs, {'number', 'table'}) |
checkTypeMulti('Module:Array.' .. funName, 1, lhs, {'number', 'table'}) |
||
checkTypeMulti('Module:Array.' .. funName, 2, rhs, {'number', 'table'}) |
checkTypeMulti('Module:Array.' .. funName, 2, rhs, {'number', 'table'}) |
||
local res = {} |
local res = setmetatable({}, getmetatable(lhs) or getmetatable(rhs)) |
||
if type(lhs) == 'number' then |
if type(lhs) == 'number' then |
||
第78行: | 第65行: | ||
end |
end |
||
else |
else |
||
assert(#lhs == #rhs, string.format(' |
assert(#lhs == #rhs, string.format('Tables are not equal length (lhs=%d, rhs=%d)', #lhs, #rhs)) |
||
for i = 1, #lhs do |
for i = 1, #lhs do |
||
res[i] = fun(lhs[i], rhs[i]) |
res[i] = fun(lhs[i], rhs[i]) |
||
第84行: | 第71行: | ||
end |
end |
||
return res |
|||
return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) |
|||
end |
end |
||
function |
function arr.__add(lhs, rhs) |
||
return mathTemplate(lhs, rhs, '__add |
return mathTemplate(lhs, rhs, '__add', function(x, y) return x + y end) |
||
end |
end |
||
function |
function arr.__sub(lhs, rhs) |
||
return mathTemplate(lhs, rhs, '__sub |
return mathTemplate(lhs, rhs, '__sub', function(x, y) return x - y end) |
||
end |
end |
||
function |
function arr.__mul(lhs, rhs) |
||
return mathTemplate(lhs, rhs, '__mul |
return mathTemplate(lhs, rhs, '__mul', function(x, y) return x * y end) |
||
end |
end |
||
function |
function arr.__div(lhs, rhs) |
||
return mathTemplate(lhs, rhs, '__div |
return mathTemplate(lhs, rhs, '__div', function(x, y) return x / y end) |
||
end |
end |
||
function |
function arr.__pow(lhs, rhs) |
||
return mathTemplate(lhs, rhs, '__pow |
return mathTemplate(lhs, rhs, '__pow', function(x, y) return x ^ y end) |
||
end |
end |
||
function |
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 |
if #lhs ~= #rhs then |
||
return false |
return false |
||
第119行: | 第124行: | ||
end |
end |
||
function arr.all(array, fn) |
|||
---Behaviour depends on the value of `fn`: |
|||
checkType('Module:Array.all', 1, array, 'table') |
|||
---* `nil` - Checks that the array doesn't contain any **false** elements. |
|||
---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for every element. |
|||
---* `number` | `table` | `boolean` - Checks that all elements in `arr` are equal to this value. |
|||
---@param arr any[] |
|||
---@param fn? any |
|||
---@return boolean |
|||
function Array.all(arr, fn) |
|||
checkType('Module:Array.all', 1, arr, 'table') |
|||
if fn == nil then fn = function(item) return item end end |
if fn == nil then fn = function(item) return item end end |
||
if type(fn) ~= 'function' then |
if type(fn) ~= 'function' then |
||
第134行: | 第132行: | ||
end |
end |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if not fn(array[i], i) then |
|||
---@diagnostic disable-next-line: redundant-parameter |
|||
if not fn(arr[i], i) then |
|||
return false |
return false |
||
end |
end |
||
第144行: | 第141行: | ||
end |
end |
||
function arr.any(array, fn) |
|||
---Behaviour depends on the value of `fn`: |
|||
checkType('Module:Array.any', 1, array, 'table') |
|||
---* `nil` - Checks that the array contains at least one non **false** element. |
|||
---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for at least one element. |
|||
---* `number` | `table` | `boolean` - Checks that `arr` contains this value. |
|||
---@param arr any[] |
|||
---@param fn? any |
|||
---@return boolean |
|||
function Array.any(arr, fn) |
|||
checkType('Module:Array.any', 1, arr, 'table') |
|||
if fn == nil then fn = function(item) return item end end |
if fn == nil then fn = function(item) return item end end |
||
if type(fn) ~= 'function' then |
if type(fn) ~= 'function' then |
||
第159行: | 第149行: | ||
end |
end |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if fn(array[i], i) then |
|||
---@diagnostic disable-next-line: redundant-parameter |
|||
if fn(arr[i], i) then |
|||
return true |
return true |
||
end |
end |
||
第169行: | 第158行: | ||
end |
end |
||
function arr.clean(array) |
|||
---Recursively removes all metatables. |
|||
checkType('Module:Array.clean', 1, array, 'table') |
|||
---@param arr any[] |
|||
for i = 1, #array do |
|||
---@return any[] |
|||
if type(array[i]) == 'table' then |
|||
function Array.clean(arr) |
|||
arr.clean(array[i]) |
|||
checkType('Module:Array.clean', 1, arr, 'table') |
|||
for i = 1, #arr do |
|||
if type(arr[i]) == 'table' then |
|||
Array.clean(arr[i]) |
|||
end |
end |
||
end |
end |
||
setmetatable( |
setmetatable(array, nil) |
||
return |
return array |
||
end |
end |
||
function arr.contains(array, elem, useElemTableContent) |
|||
---Make a copy of the input table. Preserves metatables. |
|||
checkType('Module:Array.contains', 1, array, 'table') |
|||
---@generic T: any[] |
|||
if type(elem) == 'table' and useElemTableContent ~= false then |
|||
---@param arr T |
|||
local elemMap = {} |
|||
---@param deep? boolean # Recursively clone subtables if **true**. |
|||
local isFound = {} |
|||
---@return T |
|||
arr.each(elem, function(x, i) elemMap[x] = i; isFound[i] = false end) |
|||
function Array.clone(arr, deep) |
|||
for i = 1, #array do |
|||
checkType('Module:Array.clone', 1, arr, 'table') |
|||
local j = elemMap[array[i]] |
|||
checkType('Module:Array.clone', 2, deep, 'boolean', true) |
|||
if j then |
|||
local res = {} |
|||
isFound[j] = true |
|||
for i = 1, #arr do |
|||
end |
|||
if deep == true and type(arr[i]) == 'table' then |
|||
res[i] = Array.clone(arr[i], true) |
|||
else |
|||
res[i] = arr[i] |
|||
end |
end |
||
return arr.all(isFound, true) |
|||
else |
|||
return arr.any(array, function(item) return item == elem end) |
|||
end |
end |
||
return setmetatable(res, getmetatable(arr)) |
|||
end |
end |
||
function arr.count(array, fn) |
|||
---Check if `arr` contains `val`. |
|||
checkType('Module:Array.count', 1, array, 'table') |
|||
---@param arr any[] |
|||
if fn == nil then fn = function(item) return item end end |
|||
---@param val any |
|||
if type(fn) ~= 'function' then |
|||
---@return boolean |
|||
local val = fn |
|||
function Array.contains(arr, val) |
|||
fn = function(item) return item == val end |
|||
checkType('Module:Array.contains', 1, arr, 'table') |
|||
for i = 1, #arr do |
|||
if arr[i] == val then |
|||
return true |
|||
end |
|||
end |
|||
return false |
|||
end |
|||
---Check if `arr` contains any of the values in the table `t`. |
|||
---@param arr any[] |
|||
---@param t any[] |
|||
---@return boolean |
|||
function Array.containsAny(arr, t) |
|||
checkType('Module:Array.containsAny', 1, arr, 'table') |
|||
checkType('Module:Array.containsAny', 2, t, 'table') |
|||
local lookupTbl = {} |
|||
for i = 1, #t do |
|||
lookupTbl[t[i]] = true |
|||
end |
|||
for i = 1, #arr do |
|||
if lookupTbl[arr[i]] then |
|||
return true |
|||
end |
|||
end |
|||
return false |
|||
end |
|||
---Check if `arr` contains all values in the table `t`. |
|||
---@param arr any[] |
|||
---@param t any[] |
|||
---@return boolean |
|||
function Array.containsAll(arr, t) |
|||
checkType('Module:Array.containsAll', 1, arr, 'table') |
|||
checkType('Module:Array.containsAll', 2, t, 'table') |
|||
local lookupTbl = {} |
|||
local l = #t |
|||
local trueCount = 0 |
|||
for i = 1, l do |
|||
lookupTbl[t[i]] = false |
|||
end |
|||
for i = 1, #arr do |
|||
if lookupTbl[arr[i]] == false then |
|||
lookupTbl[arr[i]] = true |
|||
trueCount = trueCount + 1 |
|||
end |
|||
if trueCount == l then |
|||
return true |
|||
end |
|||
end |
|||
return false |
|||
end |
|||
---Convolute two number arrays. |
|||
---@generic T: number[] |
|||
---@param x T |
|||
---@param y T |
|||
---@return T |
|||
function Array.convolve(x, y) |
|||
checkType('Module:Array.convolve', 1, x, 'table') |
|||
checkType('Module:Array.convolve', 2, y, 'table') |
|||
local z = {} |
|||
local xLen, yLen = #x, #y |
|||
for j = 1, (xLen + yLen - 1) do |
|||
local sum = 0 |
|||
for k = math.max(1, j - yLen + 1), math.min(xLen, j) do |
|||
sum = sum + x[k] * y[j-k+1] |
|||
end |
|||
z[j] = sum |
|||
end |
|||
return setmetatable(z, getmetatable(x) or getmetatable(y)) |
|||
end |
|||
---Remove **nil** values from `arr` while preserving order. |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@return T |
|||
function Array.condenseSparse(arr) |
|||
checkType('Module:Array.condenseSparse', 1, arr, 'table') |
|||
local keys = {} |
|||
local res = {} |
|||
local l = 0 |
|||
for k in pairs(arr) do |
|||
l = l + 1 |
|||
keys[l] = k |
|||
end |
|||
table.sort(keys) |
|||
for i = 1, l do |
|||
res[i] = arr[keys[i]] |
|||
end |
|||
return setmetatable(res, getmetatable(arr)) |
|||
end |
|||
---Behaviour depends on value of `val`: |
|||
---* `nil` - Counts the number of non **false** elements. |
|||
---* `fun(elem: any): boolean` - Count the number of times the function returned **true**. |
|||
---* `boolean` | `number` | `table` - Counts the number of times this value occurs in `arr`. |
|||
---@param arr any[] |
|||
---@param val? any |
|||
---@return integer |
|||
function Array.count(arr, val) |
|||
checkType('Module:Array.count', 1, arr, 'table') |
|||
if val == nil then val = function(item) return item end end |
|||
if type(val) ~= 'function' then |
|||
local _val = val |
|||
val = function(item) return item == _val end |
|||
end |
end |
||
local count = 0 |
local count = 0 |
||
for i = 1, # |
for i = 1, #array do |
||
if |
if fn(array[i]) then |
||
count = count + 1 |
count = count + 1 |
||
end |
end |
||
第323行: | 第203行: | ||
end |
end |
||
function arr.diff(array, order) |
|||
---Differentiate the array |
|||
checkType('Module:Array.diff', 1, array, 'table') |
|||
---@generic T: number[] |
|||
---@param arr T |
|||
---@param order number? # Oder of the differentiation. Default is 1. |
|||
---@return T # Length is `#arr - order` |
|||
function Array.diff(arr, order) |
|||
checkType('Module:Array.diff', 1, arr, 'table') |
|||
checkType('Module:Array.diff', 2, order, 'number', true) |
checkType('Module:Array.diff', 2, order, 'number', true) |
||
local res = {} |
local res = setmetatable({}, getmetatable(array)) |
||
for i = 1, # |
for i = 1, #array - 1 do |
||
res[i] = |
res[i] = array[i+1] - array[i] |
||
end |
end |
||
if order and order > 1 then |
if order and order > 1 then |
||
return |
return arr.diff(res, order - 1) |
||
end |
end |
||
return |
return res |
||
end |
end |
||
function arr.each(array, fn) |
|||
---Loops over `arr` and passes each element as the first argument to `fn`. This function returns nothing. |
|||
checkType('Module:Array.each', 1, array, 'table') |
|||
---@param arr any[] |
|||
---@param fn fun(elem: any, i?: integer) |
|||
function Array.each(arr, fn) |
|||
checkType('Module:Array.each', 1, arr, 'table') |
|||
checkType('Module:Array.each', 2, fn, 'function') |
checkType('Module:Array.each', 2, fn, 'function') |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
fn( |
fn(array[i], i) |
||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
end |
end |
||
function arr.filter(array, fn) |
|||
---Makes a copy of `arr` with only elements for which `fn` returned **true**. |
|||
checkType('Module:Array.filter', 1, array, 'table') |
|||
---@generic T: any[] |
|||
if fn == nil then fn = function(item) return item end end |
|||
---@param arr T |
|||
if type(fn) ~= 'function' then |
|||
---@param fn fun(elem: any, i?: integer): boolean |
|||
local val = fn |
|||
---@return T |
|||
fn = function(item) return item == val end |
|||
function Array.filter(arr, fn) |
|||
end |
|||
checkType('Module:Array.filter', 1, arr, 'table') |
|||
local r = setmetatable({}, getmetatable(array)) |
|||
checkType('Module:Array.filter', 2, fn, 'function') |
|||
local r = {} |
|||
local len = 0 |
local len = 0 |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if fn( |
if fn(array[i], i) then |
||
len = len + 1 |
len = len + 1 |
||
r[len] = |
r[len] = array[i] |
||
end |
end |
||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.find(array, fn, default) |
|||
---Find the first elements for which `fn` returns **true**. |
|||
checkType('Module:Array.find', 1, array, 'table') |
|||
---@param arr any[] |
|||
---@param fn any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`. |
|||
---@param default? any # Value to return if no element passes the test. |
|||
---@return any? elem # The first element that passed the test. |
|||
---@return integer? i # The index of the item that passed the test. |
|||
function Array.find(arr, fn, default) |
|||
checkType('Module:Array.find', 1, arr, 'table') |
|||
checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'}) |
checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'}) |
||
if type(fn) ~= 'function' then |
if type(fn) ~= 'function' then |
||
local |
local val = fn |
||
fn = function(item) return item == |
fn = function(item) return item == val end |
||
end |
end |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if fn(array[i], i) then |
|||
---@diagnostic disable-next-line: redundant-parameter |
|||
return array[i], i |
|||
return arr[i], i |
|||
end |
end |
||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
return default |
return default |
||
end |
end |
||
function arr.find_index(array, fn, default) |
|||
---Find the index of `val`. |
|||
checkType('Module:Array.find_index', 1, array, 'table') |
|||
---@param arr any[] |
|||
checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'}) |
|||
---@param val any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`. |
|||
if type(fn) ~= 'function' then |
|||
---@param default? any # Value to return if no element passes the test. |
|||
local val = fn |
|||
---@return integer? |
|||
fn = function(item) return item == val end |
|||
function Array.find_index(arr, val, default) |
|||
checkType('Module:Array.find_index', 1, arr, 'table') |
|||
checkTypeMulti('Module:Array.find_index', 2, val, {'function', 'table', 'number', 'boolean'}) |
|||
if type(val) ~= 'function' then |
|||
local _val = val |
|||
val = function(item) return item == _val end |
|||
end |
end |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if fn(array[i], i) then |
|||
---@diagnostic disable-next-line: redundant-parameter |
|||
if val(arr[i], i) then |
|||
return i |
return i |
||
end |
end |
||
第422行: | 第280行: | ||
end |
end |
||
function arr.newIncrementor(start, step) |
|||
---Extracts a subset of `arr`. |
|||
checkType('Module:Array.newIncrementor', 1, start, 'number', true) |
|||
---@generic T: any[] |
|||
checkType('Module:Array.newIncrementor', 2, step, 'number', true) |
|||
---@param arr T |
|||
step = step or 1 |
|||
---@param indexes integer|integer[] # Indexes of the elements. |
|||
local n = (start or 1) - step |
|||
---@return T |
|||
local obj = {} |
|||
function Array.get(arr, indexes) |
|||
return setmetatable(obj, { |
|||
checkType('Module:Array.set', 1, arr, 'table') |
|||
__call = function() n = n + step return n end, |
|||
checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'}) |
|||
__tostring = function() return n end, |
|||
if type(indexes) == 'number' then |
|||
__index = function() return n end, |
|||
indexes = {indexes} |
|||
__newindex = function(self, k, v) |
|||
end |
|||
if k == 'step' and type(v) == 'number' then |
|||
local res = {} |
|||
step = v |
|||
for i = 1, #indexes do |
|||
elseif type(v) == 'number' then |
|||
res[i] = arr[indexes[i]] |
|||
n = v |
|||
end |
|||
end |
|||
return setmetatable(res, getmetatable(arr)) |
|||
end, |
|||
__concat = function(x, y) return tostring(x) .. tostring(y) end |
|||
}) |
|||
end |
end |
||
function arr.int(array, start, stop) |
|||
---Integrates the array. Effectively does $\left\{\sum^{n}_{start}{arr[n]} \,\Bigg|\, n \in [start, stop]\right\}$. |
|||
checkType('Module:Array.int', 1, array, 'table') |
|||
---@generic T: number[] |
|||
---@param arr T # number[] |
|||
---@param start? integer # Index where to start the summation. Defaults to 1. |
|||
---@param stop? integer # Index where to stop the summation. Defaults to #arr. |
|||
---@return T |
|||
function Array.int(arr, start, stop) |
|||
checkType('Module:Array.int', 1, arr, 'table') |
|||
checkType('Module:Array.int', 2, start, 'number', true) |
checkType('Module:Array.int', 2, start, 'number', true) |
||
checkType('Module:Array.int', 3, stop, 'number', true) |
checkType('Module:Array.int', 3, stop, 'number', true) |
||
local res = {} |
local res = setmetatable({}, getmetatable(array)) |
||
start = start or 1 |
start = start or 1 |
||
stop = stop or # |
stop = stop or #array |
||
res[1] = |
res[1] = array[start] |
||
for i = 1, stop - start do |
for i = 1, stop - start do |
||
res[i+1] = res[i] + |
res[i+1] = res[i] + array[start + i] |
||
end |
end |
||
return |
return res |
||
end |
end |
||
function arr.intersect(array1, array2) |
|||
---Returns an array with elements that are present in both tables. |
|||
checkType('Module:Array.intersect', 1, array1, 'table') |
|||
---@generic T: any[] |
|||
checkType('Module:Array.intersect', 2, array2, 'table') |
|||
---@param arr1 T |
|||
local array2Elements = {} |
|||
---@param arr2 T |
|||
local res = setmetatable({}, getmetatable(array1) or getmetatable(array2)) |
|||
---@return T |
|||
function Array.intersect(arr1, arr2) |
|||
checkType('Module:Array.intersect', 1, arr1, 'table') |
|||
checkType('Module:Array.intersect', 2, arr2, 'table') |
|||
local arr2Elements = {} |
|||
local res = {} |
|||
local len = 0 |
local len = 0 |
||
arr.each(array2, function(item) array2Elements[item] = true end) |
|||
arr.each(array1, function(item) |
|||
if |
if array2Elements[item] then |
||
len = len + 1 |
len = len + 1 |
||
res[len] = item |
res[len] = item |
||
end |
end |
||
end) |
end) |
||
return res |
|||
return setmetatable(res, getmetatable(arr1) or getmetatable(arr2)) |
|||
end |
end |
||
function arr.intersects(array1, array2) |
|||
---Checks if the two inputs have at least one element in common. |
|||
checkType('Module:Array.intersects', 1, array1, 'table') |
|||
---@param arr1 any[] |
|||
checkType('Module:Array.intersects', 2, array2, 'table') |
|||
---@param arr2 any[] |
|||
---@return boolean |
|||
function Array.intersects(arr1, arr2) |
|||
checkType('Module:Array.intersects', 1, arr1, 'table') |
|||
checkType('Module:Array.intersects', 2, arr2, 'table') |
|||
local small = {} |
local small = {} |
||
local large |
local large |
||
if # |
if #array1 <= #array2 then |
||
arr.each(array1, function(item) small[item] = true end) |
|||
large = |
large = array2 |
||
else |
else |
||
arr.each(array2, function(item) small[item] = true end) |
|||
large = |
large = array1 |
||
end |
end |
||
return |
return arr.any(large, function(item) return small[item] end) |
||
end |
end |
||
function arr.insert(array, val, index, unpackVal) |
|||
---Inserts values into `arr`. |
|||
checkType('Module:Array.insert', 1, array, 'table') |
|||
---@generic T: any[] |
|||
checkType('Module:Array.insert', 3, index, 'number', true) |
|||
---@param arr T |
|||
---@param val any # If `val` is an array and `unpackVal` is **true** then the individual elements of `val` are inserted. |
|||
---@param index? integer # Location to start the insertion. Default is at the end of `arr`. |
|||
---@param unpackVal? boolean # Default is **false**. |
|||
---@return T |
|||
---@overload fun(arr: T, val: any, unpackVal: boolean): T |
|||
function Array.insert(arr, val, index, unpackVal) |
|||
checkType('Module:Array.insert', 1, arr, 'table') |
|||
checkTypeMulti('Module:Array.insert', 3, index, {'number', 'boolean', 'nil'}) |
|||
checkType('Module:Array.insert', 4, unpackVal, 'boolean', true) |
checkType('Module:Array.insert', 4, unpackVal, 'boolean', true) |
||
local len = #array |
|||
if type(index) == 'boolean' then |
|||
unpackVal, index = index, nil |
|||
end |
|||
local len = #arr |
|||
index = index or (len + 1) |
index = index or (len + 1) |
||
local mt = getmetatable(arr) |
|||
setmetatable(arr, nil) |
|||
if type(val) == 'table' and unpackVal then |
if type(val) == 'table' and unpackVal ~= false then |
||
local len2 = #val |
local len2 = #val |
||
for i = 0, len - index do |
for i = 0, len - index do |
||
array[len + len2 - i] = array[len - i] |
|||
end |
end |
||
for i = 0, len2 - 1 do |
for i = 0, len2 - 1 do |
||
array[index + i] = val[i + 1] |
|||
end |
end |
||
else |
else |
||
table.insert( |
table.insert(array, index, val) |
||
end |
end |
||
return |
return array |
||
end |
|||
---Returns the last element of `arr`. |
|||
---@param arr any[] |
|||
---@param offset? integer |
|||
---@return any |
|||
function Array.last(arr, offset) |
|||
checkType('Module:Array.last', 1, arr, 'table') |
|||
checkType('Module:Array.last', 2, offset, 'number', true) |
|||
return arr[#arr + offset] |
|||
end |
end |
||
function arr.map(array, fn) |
|||
---Returns a new table were each element of `arr` is modified by `fn`. |
|||
checkType('Module:Array.map', 1, array, 'table') |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param fn fun(elem: any, i?: integer): any # First argument is the current element, the second argument is the index of the current element. |
|||
---@return T |
|||
function Array.map(arr, fn) |
|||
checkType('Module:Array.map', 1, arr, 'table') |
|||
checkType('Module:Array.map', 2, fn, 'function') |
checkType('Module:Array.map', 2, fn, 'function') |
||
local len = 0 |
local len = 0 |
||
local r = {} |
local r = setmetatable({}, getmetatable(array)) |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
local tmp = fn( |
local tmp = fn(array[i], i) |
||
if tmp ~= nil then |
if tmp ~= nil then |
||
len = len + 1 |
len = len + 1 |
||
第564行: | 第382行: | ||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.max_by(array, fn) |
|||
---Find the element for which `fn` returned the largest value. |
|||
checkType('Module:Array.max_by', 1, array, 'table') |
|||
---@param arr any[] |
|||
---@param fn fun(elem: any): any # The returned value needs to be comparable using the `<` operator. |
|||
---@return any elem # The element with the largest `fn` value. |
|||
---@return integer i # The index of this element. |
|||
function Array.max_by(arr, fn) |
|||
checkType('Module:Array.max_by', 1, arr, 'table') |
|||
checkType('Module:Array.max_by', 2, fn, 'function') |
checkType('Module:Array.max_by', 2, fn, 'function') |
||
return unpack( |
return unpack(arr.reduce(array, function(new, old, i) |
||
local y = fn(new) |
local y = fn(new) |
||
return y > old[2] and {new, y, i} or old |
return y > old[2] and {new, y, i} or old |
||
第581行: | 第394行: | ||
end |
end |
||
function arr.max(array) |
|||
---Find the largest value in the array. |
|||
checkType('Module:Array.max', 1, array, 'table') |
|||
---@param arr any[] # The values need to be comparable using the `<` operator. |
|||
local val, _, i = arr.max_by(array, function(x) return x end) |
|||
---@return any elem |
|||
---@return integer i # The index of the largest value. |
|||
function Array.max(arr) |
|||
checkType('Module:Array.max', 1, arr, 'table') |
|||
local val, _, i = Array.max_by(arr, function(x) return x end) |
|||
return val, i |
return val, i |
||
end |
end |
||
function arr.min(array) |
|||
---Find the smallest value in the array. |
|||
checkType('Module:Array.min', 1, array, 'table') |
|||
---@param arr any[] # The values need to be comparable using the `<` operator. |
|||
local val, _, i = arr.max_by(array, function(x) return -x end) |
|||
---@return any elem |
|||
---@return integer i # The index of the smallest value. |
|||
function Array.min(arr) |
|||
checkType('Module:Array.min', 1, arr, 'table') |
|||
local val, _, i = Array.max_by(arr, function(x) return -x end) |
|||
return val, i |
return val, i |
||
end |
end |
||
function arr.new(array) |
|||
---Turn the input table into an Array. This makes it possible to use the colon `:` operator to access the Array methods. |
|||
array = array or {} |
|||
--- |
|||
for _, v in pairs(array) do |
|||
---It also enables the use of math operators with the array. |
|||
---``` |
|||
---local x = arr.new{ 1, 2, 3 } |
|||
---local y = arr{ 4, 5, 6 } -- Alternative notation |
|||
--- |
|||
---print( -x ) --> { -1, -2, -3 } |
|||
---print( x + 2 ) --> { 3, 4, 5 } |
|||
---print( x - 2 ) --> { -1, 0, 1 } |
|||
---print( x * 2 ) --> { 2, 4, 6 } |
|||
---print( x / 2 ) --> { 0.5, 1, 1.5 } |
|||
---print( x ^ 2 ) --> { 1, 4, 9 } |
|||
--- |
|||
---print( x + y ) --> { 5, 7, 9 } |
|||
---print( x .. y ) --> { 1, 2, 3, 4, 5, 6 } |
|||
---print( (x .. y):reject{3, 4, 5} ) --> { 1, 2, 6 } |
|||
---print( x:sum() ) --> 6 |
|||
--- |
|||
---print( x:update( {1, 3}, y:get{2, 3} * 2 ) ) --> { 10, 2, 12 } |
|||
---``` |
|||
---@param arr? any[] |
|||
---@return Array |
|||
function Array.new(arr) |
|||
local obj = arr or {} |
|||
for _, v in pairs(obj) do |
|||
if type(v) == 'table' then |
if type(v) == 'table' then |
||
arr.new(v) |
|||
end |
end |
||
end |
end |
||
if getmetatable( |
if getmetatable(array) == nil then |
||
setmetatable( |
setmetatable(array, arr) |
||
end |
end |
||
return |
return array |
||
end |
end |
||
function arr.range(start, stop, step) |
|||
---Creates an object that returns a value that is `step` higher than the previous value each time it gets called. |
|||
--- |
|||
---The stored value can be read without incrementing by reading the `val` field. |
|||
--- |
|||
---A new stored value can be set through the `val` field. |
|||
--- |
|||
---A new step size can be set through the `step` field. |
|||
---``` |
|||
---local inc = arr.newIncrementor(10, 5) |
|||
---print( inc() ) --> 10 |
|||
---print( inc() ) --> 15 |
|||
---print( inc.val ) --> 15 |
|||
---inc.val = 100 |
|||
---inc.step = 20 |
|||
---print( inc.val ) --> 100 |
|||
---print( inc() ) --> 120 |
|||
---``` |
|||
---@param start? number # Default is 1. |
|||
---@param step? number # Default is 1. |
|||
---@return Incrementor |
|||
function Array.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 |
|||
---@class Incrementor |
|||
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 |
|||
---Returns a range of numbers. |
|||
---@param start number # Start value inclusive. |
|||
---@param stop number # Stop value inclusive for integers, exclusive for floats. |
|||
---@param step? number # Default is 1. |
|||
---@return Array |
|||
---@overload fun(stop: number): Array |
|||
function Array.range(start, stop, step) |
|||
checkType('Module:Array.range', 1, start, 'number') |
checkType('Module:Array.range', 1, start, 'number') |
||
checkType('Module:Array.range', 2, stop, 'number', true) |
checkType('Module:Array.range', 2, stop, 'number', true) |
||
checkType('Module:Array.range', 3, step, 'number', true) |
checkType('Module:Array.range', 3, step, 'number', true) |
||
local |
local array = setmetatable({}, arr) |
||
local len = 0 |
local len = 0 |
||
if not stop then |
if not stop then |
||
第699行: | 第433行: | ||
for i = start, stop, step or 1 do |
for i = start, stop, step or 1 do |
||
len = len + 1 |
len = len + 1 |
||
array[len] = i |
|||
end |
end |
||
return |
return array |
||
end |
end |
||
function arr.reduce(array, fn, accumulator) |
|||
---Condenses the array into a single value. |
|||
checkType('Module:Array.reduce', 1, array, 'table') |
|||
--- |
|||
---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element. |
|||
--- |
|||
---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element. |
|||
---``` |
|||
---local t = { 1, 2, 3, 4 } |
|||
---local sum = arr.reduce( t, function(elem, acc) return acc + elem end ) -- sum == 10 |
|||
---``` |
|||
---@param arr any[] |
|||
---@param fn fun(elem: any, acc: any, i?: integer): any # The result of this function becomes the `acc` for the next element. |
|||
---@param accumulator? any |
|||
---@return any # This is the last accumulator value. |
|||
function Array.reduce(arr, fn, accumulator) |
|||
checkType('Module:Array.reduce', 1, arr, 'table') |
|||
checkType('Module:Array.reduce', 2, fn, 'function') |
checkType('Module:Array.reduce', 2, fn, 'function') |
||
local acc = accumulator |
local acc = accumulator |
||
local i = 1 |
local i = 1 |
||
if acc == nil then |
if acc == nil then |
||
acc = |
acc = array[1] |
||
i = 2 |
i = 2 |
||
end |
end |
||
while |
while array[i] ~= nil do |
||
acc = fn( |
acc = fn(array[i], acc, i) |
||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
第733行: | 第454行: | ||
end |
end |
||
function arr.reject(array, fn) |
|||
---Make a copy off `arr` with certain values removed. |
|||
checkType('Module:Array.reject', 1, array, 'table') |
|||
--- |
|||
checkTypeMulti('Module:Array.reject', 2, fn, {'function', 'table', 'number', 'boolean'}) |
|||
---Behaviour for different values of `val`: |
|||
if fn == nil then fn = function(item) return item end end |
|||
---* `boolean` | `number` - Remove values equal to this. |
|||
if type(fn) ~= 'function' and type(fn) ~= 'table' then |
|||
---* `table` - Remove all values in this table. |
|||
fn = {fn} |
|||
---* `fun(elem: any, i?: integer): boolean` - Remove elements for which the functions returns **true**. |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param val table|function|number|boolean |
|||
---@return T |
|||
function Array.reject(arr, val) |
|||
checkType('Module:Array.reject', 1, arr, 'table') |
|||
checkTypeMulti('Module:Array.reject', 2, val, {'function', 'table', 'number', 'boolean'}) |
|||
if type(val) ~= 'function' and type(val) ~= 'table' then |
|||
val = {val} |
|||
end |
end |
||
local r = {} |
local r = setmetatable({}, getmetatable(array)) |
||
local len = 0 |
local len = 0 |
||
if type( |
if type(fn) == 'function' then |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if not |
if not fn(array[i], i) then |
||
len = len + 1 |
len = len + 1 |
||
r[len] = |
r[len] = array[i] |
||
end |
end |
||
i = i + 1 |
i = i + 1 |
||
第762行: | 第474行: | ||
else |
else |
||
local rejectMap = {} |
local rejectMap = {} |
||
arr.each(fn, function(item) rejectMap[item] = true end) |
|||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if not rejectMap[ |
if not rejectMap[array[i]] then |
||
len = len + 1 |
len = len + 1 |
||
r[len] = |
r[len] = array[i] |
||
end |
end |
||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.rep(val, n) |
|||
---Returns an Array with `val` repeated `n` times. |
|||
---@param val any |
|||
---@param n integer |
|||
---@return Array |
|||
function Array.rep(val, n) |
|||
checkType('Module:Array.rep', 2, n, 'number') |
checkType('Module:Array.rep', 2, n, 'number') |
||
local r = {} |
local r = setmetatable({}, arr) |
||
for i = 1, n do |
for i = 1, n do |
||
r[i] = val |
r[i] = val |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.scan(array, fn, accumulator) |
|||
checkType('Module:Array.scan', 1, array, 'table') |
|||
--- |
|||
---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element. |
|||
--- |
|||
---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element. |
|||
---``` |
|||
---local t = { 1, 2, 3, 4 } |
|||
---local x = arr.scan( t, function(elem, acc) return acc + elem end ) -- x = { 1, 3, 6, 10 } |
|||
---``` |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param fn fun(elem: any, acc: any, i?: integer): any # Returned value becomes the accumulator for the next element. |
|||
---@param accumulator? any |
|||
---@return T |
|||
function Array.scan(arr, fn, accumulator) |
|||
checkType('Module:Array.scan', 1, arr, 'table') |
|||
checkType('Module:Array.scan', 2, fn, 'function') |
checkType('Module:Array.scan', 2, fn, 'function') |
||
local acc = accumulator |
local acc = accumulator |
||
local r = {} |
local r = setmetatable({}, getmetatable(array)) |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
if i == 1 and not accumulator then |
if i == 1 and not accumulator then |
||
acc = |
acc = array[i] |
||
else |
else |
||
acc = fn( |
acc = fn(array[i], acc) |
||
end |
end |
||
r[i] = acc |
r[i] = acc |
||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.slice(array, start, finish) |
|||
---Update a range of index with a range of values. |
|||
checkType('Module:Array.slice', 1, array, 'table') |
|||
--- |
|||
---If if only one value is given but multiple indexes than that value is set for all those indexes. |
|||
--- |
|||
---If `values` is a table then it must of the same length as `indexes`. |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param indexes integer|integer[] |
|||
---@param values any|any[] |
|||
---@return T |
|||
function Array.set(arr, indexes, values) |
|||
checkType('Module:Array.set', 1, arr, 'table') |
|||
checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'}) |
|||
local mt = getmetatable(arr) |
|||
setmetatable(arr, nil) |
|||
if type(indexes) == 'number' then |
|||
indexes = {indexes} |
|||
end |
|||
if type(values) == 'table' then |
|||
assert(#indexes == #values, string.format("Module:Array.set: 'indexes' and 'values' arrays are not equal length (#indexes = %d, #values = %d)", #indexes, #values)) |
|||
for i = 1, #indexes do |
|||
arr[indexes[i]] = values[i] |
|||
end |
|||
else |
|||
for i = 1, #indexes do |
|||
arr[indexes[i]] = values |
|||
end |
|||
end |
|||
return setmetatable(arr, mt) |
|||
end |
|||
---Extract a subtable from `arr`. |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param start integer # Start index. Use negative values to count form the end of the array. |
|||
---@param stop integer # Stop index. Use negative values to count form the end of the array. |
|||
---@return T |
|||
---@overload fun(arr: T, stop: integer): T |
|||
function Array.slice(arr, start, stop) |
|||
checkType('Module:Array.slice', 1, arr, 'table') |
|||
checkType('Module:Array.slice', 2, start, 'number', true) |
checkType('Module:Array.slice', 2, start, 'number', true) |
||
checkType('Module:Array.slice', 3, |
checkType('Module:Array.slice', 3, finish, 'number', true) |
||
start = start or |
start = start or 1 |
||
finish = finish or #array |
|||
if start < 0 then |
|||
if start < 0 and finish == nil then |
|||
finish = #array + start |
|||
end |
|||
if stop == nil then |
|||
stop = start |
|||
start = 1 |
start = 1 |
||
elseif start < 0 then |
|||
start = #array + start |
|||
end |
end |
||
if |
if finish < 0 then |
||
finish = #array + finish |
|||
end |
end |
||
local r = {} |
local r = setmetatable({}, getmetatable(array)) |
||
local len = 0 |
local len = 0 |
||
for i = start, |
for i = start, finish do |
||
len = len + 1 |
len = len + 1 |
||
r[len] = |
r[len] = array[i] |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.split(array, count) |
|||
---Split `arr` into two arrays. |
|||
checkType('Module:Array.split', 1, array, 'table') |
|||
---@generic T: any[] |
|||
checkType('Module:Array.split', 2, count, 'number') |
|||
---@param arr T |
|||
local x = setmetatable({}, getmetatable(array)) |
|||
---@param index integer # Index to split on. |
|||
local y = setmetatable({}, getmetatable(array)) |
|||
---@return T x # [1, index] |
|||
for i = 1, #array do |
|||
---@return T y # [index + 1, #arr] |
|||
table.insert(i <= count and x or y, array[i]) |
|||
function Array.split(arr, index) |
|||
checkType('Module:Array.split', 1, arr, 'table') |
|||
checkType('Module:Array.split', 2, index, 'number') |
|||
local x = {} |
|||
local y = {} |
|||
for i = 1, #arr do |
|||
table.insert(i <= index and x or y, arr[i]) |
|||
end |
end |
||
return x, y |
|||
return setmetatable(x, getmetatable(arr)), setmetatable(y, getmetatable(arr)) |
|||
end |
end |
||
function arr.sum(array) |
|||
---Returns the sum of all elements of `arr`. |
|||
checkType('Module:Array.sum', 1, array, 'table') |
|||
---@param arr number[] |
|||
---@return number |
|||
function Array.sum(arr) |
|||
checkType('Module:Array.sum', 1, arr, 'table') |
|||
local res = 0 |
local res = 0 |
||
for i = 1, # |
for i = 1, #array do |
||
res = res + |
res = res + array[i] |
||
end |
end |
||
return res |
return res |
||
end |
end |
||
function arr.take(array, count, offset) |
|||
---Extract a subtable from `arr`. |
|||
checkType('Module:Array.take', 1, array, 'table') |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param count integer # Length of the subtable. |
|||
---@param start? integer # Start index. Default is 1. |
|||
---@return T |
|||
function Array.take(arr, count, start) |
|||
checkType('Module:Array.take', 1, arr, 'table') |
|||
checkType('Module:Array.take', 2, count, 'number') |
checkType('Module:Array.take', 2, count, 'number') |
||
checkType('Module:Array.take', 3, |
checkType('Module:Array.take', 3, offset, 'number', true) |
||
local x = {} |
local x = setmetatable({}, getmetatable(array)) |
||
for i = offset or 1, #array do |
|||
if i <= count then |
|||
table.insert(x, |
table.insert(x, array[i]) |
||
end |
|||
end |
end |
||
return |
return x |
||
end |
end |
||
function arr.take_every(array, n, offset) |
|||
---Extract a subtable from `arr`. |
|||
checkType('Module:Array.take_every', 1, array, 'table') |
|||
---``` |
|||
---local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } |
|||
---local x = arr.take_every( t, 2 ) --> x = { 1, 3, 5, 7, 9 } |
|||
---local x = arr.take_every( t, 2, 3 ) --> x = { 1, 3, 5 } |
|||
---local x = arr.take_every( t, 2, 3, 2 ) --> x = { 2, 4, 6 } |
|||
--- ``` |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param n integer # Step size. |
|||
---@param start? integer # Start index. |
|||
---@param count? integer # Max amount of elements to get. |
|||
---@return T |
|||
function Array.take_every(arr, n, start, count) |
|||
checkType('Module:Array.take_every', 1, arr, 'table') |
|||
checkType('Module:Array.take_every', 2, n, 'number') |
checkType('Module:Array.take_every', 2, n, 'number') |
||
checkType('Module:Array.take_every', 3, |
checkType('Module:Array.take_every', 3, offset, 'number', true) |
||
local r = setmetatable({}, getmetatable(array)) |
|||
checkType('Module:Array.take_every', 4, count, 'number', true) |
|||
count = count or #arr |
|||
local r = {} |
|||
local len = 0 |
local len = 0 |
||
local i = |
local i = offset or 1 |
||
while |
while array[i] ~= nil do |
||
len = len + 1 |
len = len + 1 |
||
r[len] = |
r[len] = array[i] |
||
i = i + n |
i = i + n |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.unique(array, fn) |
|||
---Return a new table with all duplicates removed. |
|||
checkType('Module:Array.unique', 1, array, 'table') |
|||
---@generic T: any[] |
|||
---@param arr T |
|||
---@param fn? fun(elem: any): any # Function to generate an id for each element. The result will then contain elements that generated unique ids. |
|||
---@return T |
|||
function Array.unique(arr, fn) |
|||
checkType('Module:Array.unique', 1, arr, 'table') |
|||
checkType('Module:Array.unique', 2, fn, 'function', true) |
checkType('Module:Array.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 len = 0 |
||
local hash = {} |
local hash = {} |
||
local i = 1 |
local i = 1 |
||
while |
while array[i] ~= nil do |
||
local id = fn( |
local id = fn(array[i]) |
||
if not hash[id] then |
if not hash[id] then |
||
len = len + 1 |
len = len + 1 |
||
r[len] = |
r[len] = array[i] |
||
hash[id] = true |
hash[id] = true |
||
end |
end |
||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
return |
return r |
||
end |
end |
||
function arr.update(array, indexes, values) |
|||
---Combine elements with the same index from multiple arrays. |
|||
checkType('Module:Array.update', 1, array, 'table') |
|||
---``` |
|||
checkTypeMulti('Module:Array.update', 2, indexes, {'table', 'number'}) |
|||
---local x = {1, 2, 3} |
|||
if type(indexes) == 'number' then |
|||
---local y = {4, 5, 6, 7} |
|||
indexes = {indexes} |
|||
---local z = arr.zip( x, y ) --> z = { { 1, 4 }, { 2, 5 }, { 3, 6 }, { 7 } } |
|||
---``` |
|||
---@param ... any[] |
|||
---@return Array |
|||
function Array.zip(...) |
|||
local arrs = { ... } |
|||
checkType('Module:Array.zip', 1, arrs[1], 'table') |
|||
local r = {} |
|||
local _, longest = Array.max_by(arrs, function(arr) return #arr end) |
|||
for i = 1, longest do |
|||
local q = {} |
|||
for j = 1, #arrs do |
|||
table.insert(q, arrs[j][i]) |
|||
end |
|||
table.insert(r, setmetatable(q, Array)) |
|||
end |
end |
||
if type(values) == 'table' then |
|||
return setmetatable(r, Array) |
|||
assert(#indexes == #values, 'Values array must be of equal length as index array') |
|||
end |
|||
for i = 1, #indexes do |
|||
array[indexes[i]] = values[i] |
|||
-- Range indexing has a performance impact so this is placed in a separate subclass |
|||
Array.RI_mt = {} |
|||
for k, v in pairs(Array) do |
|||
Array.RI_mt[k] = v |
|||
end |
|||
function Array.RI_mt.__index(t, k) |
|||
if type(k) == 'table' then |
|||
local res = {} |
|||
for i = 1, #k do |
|||
res[i] = t[k[i]] |
|||
end |
end |
||
return setmetatable(res, Array) |
|||
else |
else |
||
for i = 1, #indexes do |
|||
return Array[k] |
|||
array[indexes[i]] = values |
|||
end |
|||
end |
|||
function Array.RI_mt.__newindex(t, k, v) |
|||
if type(k) == 'table' then |
|||
if type(v) == 'table' then |
|||
for i = 1, #k do |
|||
t[k[i]] = v[i] |
|||
end |
|||
else |
|||
for i = 1, #k do |
|||
t[k[i]] = v |
|||
end |
|||
end |
end |
||
else |
|||
rawset(t, k, v) |
|||
end |
end |
||
return array |
|||
end |
end |
||
function arr.zip(...) |
|||
---Enable range indexing on the input array. |
|||
local arrays = { ... } |
|||
--- |
|||
checkType('Module:Array.zip', 1, arrays[1], 'table') |
|||
---This has a performance impact on reads and writes to the table. |
|||
local r = setmetatable({}, getmetatable(arrays[1])) |
|||
---``` |
|||
local _, longest = arr.max_by(arrays, function(array) return #array end) |
|||
for i = 1, longest do |
|||
---print( t[{2, 3}] ) --> { 11, 12 } |
|||
local q = {} |
|||
---``` |
|||
for j = 1, #arrays do |
|||
---@param arr any[] |
|||
table.insert(q, arrays[j][i]) |
|||
---@param recursive? boolean # Default is false. |
|||
---@return Array |
|||
function Array.ri(arr, recursive) |
|||
checkType('Module:Array.ri', 1, arr, 'table') |
|||
checkType('Module:Array.ri', 2, recursive, 'boolean', true) |
|||
arr = arr or {} |
|||
if recursive then |
|||
for _, v in pairs(arr) do |
|||
if type(v) == 'table' then |
|||
Array.ri(v, true) |
|||
end |
|||
end |
end |
||
table.insert(r, q) |
|||
end |
end |
||
return r |
|||
if getmetatable(arr) == nil or getmetatable(arr) == Array then |
|||
setmetatable(arr, Array.RI_mt) |
|||
end |
|||
return arr |
|||
end |
|||
---Globally enable range indexing on all Array objects by default. |
|||
---@param set boolean |
|||
function Array.allwaysAllowRangeIndexing(set) |
|||
checkType('Module:Array.allwaysAllowRangeIndexing', 1, set, 'boolean') |
|||
if set then |
|||
Array.__index = Array.RI_mt.__index |
|||
Array.__newindex = Array.RI_mt.__newindex |
|||
else |
|||
Array.__index = Array |
|||
Array.__newindex = nil |
|||
end |
|||
end |
end |
||
return |
return arr |
||
-- </nowiki> |
2023年8月6日 (日) 08:04的版本
可在Module:Array/doc创建此模块的帮助文档
-- <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>