Module:Array: Difference between revisionsGive feedback
osrsw>CephHunter Fix param order on take_every |
m 16 revisions imported |
||
| (One intermediate revision by one other user not shown) | |||
| Line 2: | Line 2: | ||
local checkType = libraryUtil.checkType | local checkType = libraryUtil.checkType | ||
local checkTypeMulti = libraryUtil.checkTypeMulti | local checkTypeMulti = libraryUtil.checkTypeMulti | ||
---Returns the length of the array but it also works on proxy arrays | |||
---@param arr any[] | |||
---@return integer | |||
local function len(arr) | |||
local l = #arr | |||
if l == 0 then | |||
if arr[1] ~= nil then | |||
-- Exponential search to find length of proxy table | |||
local low = 1 | |||
local high = 1 | |||
local ceil = math.ceil | |||
while arr[high] ~= nil do | |||
high = high * 2 | |||
end | |||
while low ~= high do | |||
local m = ceil((low + high) / 2) | |||
if arr[m] == nil then | |||
high = m - 1 | |||
else | |||
low = m | |||
end | |||
end | |||
return low | |||
else | |||
return 0 | |||
end | |||
else | |||
return l | |||
end | |||
end | |||
---@class Array | ---@class Array | ||
| Line 14: | Line 45: | ||
---@operator pow(number|number[]|Array): Array | ---@operator pow(number|number[]|Array): Array | ||
local Array = { | local Array = { | ||
pop = table.remove | pop = table.remove, | ||
len = len | |||
} | } | ||
Array.__index = Array | Array.__index = Array | ||
| Line 24: | Line 56: | ||
end | end | ||
}) | }) | ||
function Array.__concat(lhs, rhs) | function Array.__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 = {} | ||
for i = 1, | local l1 = len(lhs) | ||
for i = 1, l1 do | |||
res[i] = lhs[i] | res[i] = lhs[i] | ||
end | end | ||
for i = 1, len(rhs) do | |||
for i = 1, | res[l1 + i] = rhs[i] | ||
res[i | |||
end | end | ||
return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) | return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) | ||
| Line 68: | Line 89: | ||
if type(lhs) == 'number' then | if type(lhs) == 'number' then | ||
for i = 1, | for i = 1, len(rhs) do | ||
res[i] = fun(lhs, rhs[i]) | res[i] = fun(lhs, rhs[i]) | ||
end | end | ||
elseif type(rhs) == 'number' then | elseif type(rhs) == 'number' then | ||
for i = 1, | for i = 1, len(lhs) do | ||
res[i] = fun(lhs[i], rhs) | res[i] = fun(lhs[i], rhs) | ||
end | end | ||
else | else | ||
assert( | assert(len(lhs) == len(rhs), string.format('Elementwise %s failed because arrays have different sizes (left: %d, right: %d)', opName, len(lhs), len(rhs))) | ||
for i = 1, | for i = 1, len(lhs) do | ||
res[i] = fun(lhs[i], rhs[i]) | res[i] = fun(lhs[i], rhs[i]) | ||
end | end | ||
| Line 106: | Line 127: | ||
function Array.__eq(lhs, rhs) | function Array.__eq(lhs, rhs) | ||
if | if len(lhs) ~= len(rhs) then | ||
return false | return false | ||
end | end | ||
for i = 1, | for i = 1, len(lhs) do | ||
if lhs[i] ~= rhs[i] then | if lhs[i] ~= rhs[i] then | ||
return false | return false | ||
| Line 131: | Line 152: | ||
fn = function(item) return item == val end | fn = function(item) return item == val end | ||
end | end | ||
for i = 1, len(arr) do | |||
---@diagnostic disable-next-line: redundant-parameter | ---@diagnostic disable-next-line: redundant-parameter | ||
if not fn(arr[i], i) then | if not fn(arr[i], i) then | ||
return false | return false | ||
end | end | ||
end | end | ||
return true | return true | ||
| Line 156: | Line 175: | ||
fn = function(item) return item == val end | fn = function(item) return item == val end | ||
end | end | ||
for i = 1, len(arr) do | |||
---@diagnostic disable-next-line: redundant-parameter | ---@diagnostic disable-next-line: redundant-parameter | ||
if fn(arr[i], i) then | if fn(arr[i], i) then | ||
return true | return true | ||
end | end | ||
end | end | ||
return false | return false | ||
| Line 172: | Line 189: | ||
function Array.clean(arr) | function Array.clean(arr) | ||
checkType('Module:Array.clean', 1, arr, 'table') | checkType('Module:Array.clean', 1, arr, 'table') | ||
for i = 1, | for i = 1, len(arr) do | ||
if type(arr[i]) == 'table' then | if type(arr[i]) == 'table' then | ||
Array.clean(arr[i]) | Array.clean(arr[i]) | ||
| Line 190: | Line 207: | ||
checkType('Module:Array.clone', 2, deep, 'boolean', true) | checkType('Module:Array.clone', 2, deep, 'boolean', true) | ||
local res = {} | local res = {} | ||
for i = 1, | for i = 1, len(arr) do | ||
if deep == true and type(arr[i]) == 'table' then | if deep == true and type(arr[i]) == 'table' then | ||
res[i] = Array.clone(arr[i], true) | res[i] = Array.clone(arr[i], true) | ||
| Line 206: | Line 223: | ||
function Array.contains(arr, val) | function Array.contains(arr, val) | ||
checkType('Module:Array.contains', 1, arr, 'table') | checkType('Module:Array.contains', 1, arr, 'table') | ||
for i = 1, | for i = 1, len(arr) do | ||
if arr[i] == val then | if arr[i] == val then | ||
return true | return true | ||
| Line 222: | Line 239: | ||
checkType('Module:Array.containsAny', 2, t, 'table') | checkType('Module:Array.containsAny', 2, t, 'table') | ||
local lookupTbl = {} | local lookupTbl = {} | ||
for i = 1, | for i = 1, len(t) do | ||
lookupTbl[t[i]] = true | lookupTbl[t[i]] = true | ||
end | end | ||
for i = 1, | for i = 1, len(arr) do | ||
if lookupTbl[arr[i]] then | if lookupTbl[arr[i]] then | ||
return true | return true | ||
| Line 241: | Line 258: | ||
checkType('Module:Array.containsAll', 2, t, 'table') | checkType('Module:Array.containsAll', 2, t, 'table') | ||
local lookupTbl = {} | local lookupTbl = {} | ||
local trueCount = 0 | local trueCount = 0 | ||
local l = len(t) | |||
for i = 1, l do | for i = 1, l do | ||
lookupTbl[t[i]] = false | lookupTbl[t[i]] = false | ||
end | end | ||
for i = 1, | for i = 1, len(arr) do | ||
if lookupTbl[arr[i]] == false then | if lookupTbl[arr[i]] == false then | ||
lookupTbl[arr[i]] = true | lookupTbl[arr[i]] = true | ||
| Line 267: | Line 284: | ||
checkType('Module:Array.convolve', 2, y, 'table') | checkType('Module:Array.convolve', 2, y, 'table') | ||
local z = {} | local z = {} | ||
local xLen, yLen = | local xLen, yLen = len(x), len(y) | ||
for j = 1, (xLen + yLen - 1) do | for j = 1, (xLen + yLen - 1) do | ||
local sum = 0 | local sum = 0 | ||
| Line 313: | Line 330: | ||
end | end | ||
local count = 0 | local count = 0 | ||
for i = 1, | for i = 1, len(arr) do | ||
if val(arr[i]) then | if val(arr[i]) then | ||
count = count + 1 | count = count + 1 | ||
| Line 330: | Line 347: | ||
checkType('Module:Array.diff', 2, order, 'number', true) | checkType('Module:Array.diff', 2, order, 'number', true) | ||
local res = {} | local res = {} | ||
for i = 1, | for i = 1, len(arr) - 1 do | ||
res[i] = arr[i+1] - arr[i] | res[i] = arr[i+1] - arr[i] | ||
end | end | ||
| Line 345: | Line 362: | ||
checkType('Module:Array.each', 1, arr, 'table') | checkType('Module:Array.each', 1, arr, 'table') | ||
checkType('Module:Array.each', 2, fn, 'function') | checkType('Module:Array.each', 2, fn, 'function') | ||
for i = 1, len(arr) do | |||
fn(arr[i], i) | fn(arr[i], i) | ||
end | end | ||
end | end | ||
| Line 361: | Line 376: | ||
checkType('Module:Array.filter', 2, fn, 'function') | checkType('Module:Array.filter', 2, fn, 'function') | ||
local r = {} | local r = {} | ||
local | local l = 0 | ||
for i = 1, len(arr) do | |||
if fn(arr[i], i) then | if fn(arr[i], i) then | ||
l = l + 1 | |||
r[ | r[l] = arr[i] | ||
end | end | ||
end | end | ||
return setmetatable(r, getmetatable(arr)) | return setmetatable(r, getmetatable(arr)) | ||
| Line 386: | Line 399: | ||
fn = function(item) return item == _val end | fn = function(item) return item == _val end | ||
end | end | ||
for i = 1, len(arr) do | |||
---@diagnostic disable-next-line: redundant-parameter | ---@diagnostic disable-next-line: redundant-parameter | ||
if fn(arr[i], i) then | if fn(arr[i], i) then | ||
return arr[i], i | return arr[i], i | ||
end | end | ||
end | end | ||
return default, nil | return default, nil | ||
| Line 409: | Line 420: | ||
val = function(item) return item == _val end | val = function(item) return item == _val end | ||
end | end | ||
for i = 1, len(arr) do | |||
---@diagnostic disable-next-line: redundant-parameter | ---@diagnostic disable-next-line: redundant-parameter | ||
if val(arr[i], i) then | if val(arr[i], i) then | ||
return i | return i | ||
end | end | ||
end | end | ||
return default | return default | ||
| Line 432: | Line 441: | ||
end | end | ||
local res = {} | local res = {} | ||
for i = 1, | for i = 1, len(indexes) do | ||
res[i] = arr[indexes[i]] | res[i] = arr[indexes[i]] | ||
end | end | ||
| Line 450: | Line 459: | ||
local res = {} | local res = {} | ||
start = start or 1 | start = start or 1 | ||
stop = stop or | stop = stop or len(arr) | ||
res[1] = arr[start] | res[1] = arr[start] | ||
for i = 1, stop - start do | for i = 1, stop - start do | ||
| Line 468: | Line 477: | ||
local arr2Elements = {} | local arr2Elements = {} | ||
local res = {} | local res = {} | ||
local | local l = 0 | ||
Array.each(arr2, function(item) arr2Elements[item] = true end) | Array.each(arr2, function(item) arr2Elements[item] = true end) | ||
Array.each(arr1, function(item) | Array.each(arr1, function(item) | ||
if arr2Elements[item] then | if arr2Elements[item] then | ||
l = l + 1 | |||
res[ | res[l] = item | ||
end | end | ||
end) | end) | ||
| Line 488: | Line 497: | ||
local small = {} | local small = {} | ||
local large | local large | ||
if | if len(arr1) <= len(arr2) then | ||
Array.each(arr1, function(item) small[item] = true end) | Array.each(arr1, function(item) small[item] = true end) | ||
large = arr2 | large = arr2 | ||
| Line 513: | Line 522: | ||
unpackVal, index = index, nil | unpackVal, index = index, nil | ||
end | end | ||
local len | local l = len(arr) | ||
index = index or ( | index = index or (l + 1) | ||
local mt = getmetatable(arr) | local mt = getmetatable(arr) | ||
setmetatable(arr, nil) | setmetatable(arr, nil) | ||
if type(val) == 'table' | if unpackVal and type(val) == 'table' then | ||
local | local l2 = len(val) | ||
for i = 0, | for i = 0, l - index do | ||
arr[ | arr[l + l2 - i] = arr[l - i] | ||
end | end | ||
for i = 0, | for i = 0, l2 - 1 do | ||
arr[index + i] = val[i + 1] | arr[index + i] = val[i + 1] | ||
end | end | ||
| Line 540: | Line 549: | ||
checkType('Module:Array.last', 1, arr, 'table') | checkType('Module:Array.last', 1, arr, 'table') | ||
checkType('Module:Array.last', 2, offset, 'number', true) | checkType('Module:Array.last', 2, offset, 'number', true) | ||
return arr[ | return arr[len(arr) + offset] | ||
end | end | ||
| Line 551: | Line 560: | ||
checkType('Module:Array.map', 1, arr, 'table') | checkType('Module:Array.map', 1, arr, 'table') | ||
checkType('Module:Array.map', 2, fn, 'function') | checkType('Module:Array.map', 2, fn, 'function') | ||
local | local l = 0 | ||
local r = {} | local r = {} | ||
for i = 1, len(arr) do | |||
local tmp = fn(arr[i], i) | local tmp = fn(arr[i], i) | ||
if tmp ~= nil then | if tmp ~= nil then | ||
l = l + 1 | |||
r[ | r[l] = tmp | ||
end | end | ||
end | end | ||
return setmetatable(r, getmetatable(arr)) | return setmetatable(r, getmetatable(arr)) | ||
| Line 666: | Line 673: | ||
return setmetatable(obj, { | return setmetatable(obj, { | ||
__call = function() n = n + step return n end, | __call = function() n = n + step return n end, | ||
__tostring = function() return n end, | __tostring = function() return tostring(n) end, | ||
__index = function() return n end, | __index = function() return n end, | ||
__newindex = function(self, k, v) | __newindex = function(self, k, v) | ||
| Line 719: | Line 726: | ||
checkType('Module:Array.reduce', 2, fn, 'function') | checkType('Module:Array.reduce', 2, fn, 'function') | ||
local acc = accumulator | local acc = accumulator | ||
local | local start = 1 | ||
if acc == nil then | if acc == nil then | ||
acc = arr[1] | acc = arr[1] | ||
start = 2 | |||
end | end | ||
for i = start, len(arr) do | |||
acc = fn(arr[i], acc, i) | acc = fn(arr[i], acc, i) | ||
end | end | ||
return acc | return acc | ||
| Line 748: | Line 754: | ||
end | end | ||
local r = {} | local r = {} | ||
local | local l = 0 | ||
if type(val) == 'function' then | if type(val) == 'function' then | ||
for i = 1, len(arr) do | |||
if not val(arr[i], i) then | if not val(arr[i], i) then | ||
l = l + 1 | |||
r[ | r[l] = arr[i] | ||
end | end | ||
end | end | ||
else | else | ||
local rejectMap = {} | local rejectMap = {} | ||
Array.each(val --[[@as any[] ]], function(item) rejectMap[item] = true end) | Array.each(val --[[@as any[] ]], function(item) rejectMap[item] = true end) | ||
for i = 1, len(arr) do | |||
if not rejectMap[arr[i]] then | if not rejectMap[arr[i]] then | ||
l = l + 1 | |||
r[ | r[l] = arr[i] | ||
end | end | ||
end | end | ||
end | end | ||
| Line 805: | Line 807: | ||
local acc = accumulator | local acc = accumulator | ||
local r = {} | local r = {} | ||
for i = 1, len(arr) do | |||
if i == 1 and not accumulator then | if i == 1 and not accumulator then | ||
acc = arr[i] | acc = arr[i] | ||
| Line 813: | Line 814: | ||
end | end | ||
r[i] = acc | r[i] = acc | ||
end | end | ||
return setmetatable(r, getmetatable(arr)) | return setmetatable(r, getmetatable(arr)) | ||
| Line 837: | Line 837: | ||
end | end | ||
if type(values) == 'table' then | if type(values) == 'table' then | ||
assert( | assert(len(indexes) == len(values), string.format("Module:Array.set: 'indexes' and 'values' arrays are not equal length (#indexes = %d, #values = %d)", len(indexes), len(values))) | ||
for i = 1, | for i = 1, len(indexes) do | ||
arr[indexes[i]] = values[i] | arr[indexes[i]] = values[i] | ||
end | end | ||
else | else | ||
for i = 1, | for i = 1, len(indexes) do | ||
arr[indexes[i]] = values | arr[indexes[i]] = values | ||
end | end | ||
| Line 860: | Line 860: | ||
checkType('Module:Array.slice', 2, start, 'number', true) | checkType('Module:Array.slice', 2, start, 'number', true) | ||
checkType('Module:Array.slice', 3, stop, 'number', true) | checkType('Module:Array.slice', 3, stop, 'number', true) | ||
start = start or | start = start or len(arr) | ||
if start < 0 then | if start < 0 then | ||
start = | start = len(arr) + start | ||
end | end | ||
if stop == nil then | if stop == nil then | ||
| Line 869: | Line 869: | ||
end | end | ||
if stop < 0 then | if stop < 0 then | ||
stop = | stop = len(arr) + stop | ||
end | end | ||
local r = {} | local r = {} | ||
| Line 891: | Line 891: | ||
local x = {} | local x = {} | ||
local y = {} | local y = {} | ||
for i = 1, | for i = 1, len(arr) do | ||
table.insert(i <= index and x or y, arr[i]) | table.insert(i <= index and x or y, arr[i]) | ||
end | end | ||
| Line 903: | Line 903: | ||
checkType('Module:Array.sum', 1, arr, 'table') | checkType('Module:Array.sum', 1, arr, 'table') | ||
local res = 0 | local res = 0 | ||
for i = 1, | for i = 1, len(arr) do | ||
res = res + arr[i] | res = res + arr[i] | ||
end | end | ||
| Line 921: | Line 921: | ||
local x = {} | local x = {} | ||
start = start or 1 | start = start or 1 | ||
for i = start, math.min( | for i = start, math.min(len(arr), count + start - 1) do | ||
table.insert(x, arr[i]) | table.insert(x, arr[i]) | ||
end | end | ||
| Line 931: | Line 931: | ||
---local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } | ---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 ) --> x = { 1, 3, 5, 7, 9 } | ||
---local x = arr.take_every( t, 2, 3 ) --> x = { | ---local x = arr.take_every( t, 2, 3 ) --> x = { 3, 5, 7, 9 } | ||
---local x = arr.take_every( t, 2, 3, 2 ) --> x = { | ---local x = arr.take_every( t, 2, 3, 2 ) --> x = { 3, 5 } | ||
--- ``` | --- ``` | ||
---@generic T: any[] | ---@generic T: any[] | ||
| Line 945: | Line 945: | ||
checkType('Module:Array.take_every', 3, start, 'number', true) | checkType('Module:Array.take_every', 3, start, 'number', true) | ||
checkType('Module:Array.take_every', 4, count, 'number', true) | checkType('Module:Array.take_every', 4, count, 'number', true) | ||
count = count or | count = count or len(arr) | ||
start = start or 1 | |||
local stop = math.min(len(arr), start + n * (count - 1)) | |||
local r = {} | local r = {} | ||
local | local l = 0 | ||
for i = start, stop, n do | |||
l = l + 1 | |||
r[l] = arr[i] | |||
r[ | |||
end | end | ||
return setmetatable(r, getmetatable(arr)) | return setmetatable(r, getmetatable(arr)) | ||
| Line 967: | Line 967: | ||
fn = fn or function(item) return item end | fn = fn or function(item) return item end | ||
local r = {} | local r = {} | ||
local | local l = 0 | ||
local hash = {} | local hash = {} | ||
for i = 1, len(arr) do | |||
local id = fn(arr[i]) | local id = fn(arr[i]) | ||
if not hash[id] then | if not hash[id] then | ||
l = l + 1 | |||
r[ | r[l] = arr[i] | ||
hash[id] = true | hash[id] = true | ||
end | end | ||
end | end | ||
return setmetatable(r, getmetatable(arr)) | return setmetatable(r, getmetatable(arr)) | ||
| Line 994: | Line 992: | ||
checkType('Module:Array.zip', 1, arrs[1], 'table') | checkType('Module:Array.zip', 1, arrs[1], 'table') | ||
local r = {} | local r = {} | ||
local _, longest = Array.max_by(arrs, function(arr) return | local _, longest = Array.max_by(arrs, function(arr) return len(arr) end) | ||
for i = 1, longest do | for i = 1, longest do | ||
local q = {} | local q = {} | ||
for j = 1, | for j = 1, len(arrs) do | ||
table.insert(q, arrs[j][i]) | table.insert(q, arrs[j][i]) | ||
end | end | ||
| Line 1,014: | Line 1,012: | ||
if type(k) == 'table' then | if type(k) == 'table' then | ||
local res = {} | local res = {} | ||
for i = 1, | for i = 1, len(k) do | ||
res[i] = t[k[i]] | res[i] = t[k[i]] | ||
end | end | ||
| Line 1,026: | Line 1,024: | ||
if type(k) == 'table' then | if type(k) == 'table' then | ||
if type(v) == 'table' then | if type(v) == 'table' then | ||
for i = 1, | for i = 1, len(k) do | ||
t[k[i]] = v[i] | t[k[i]] = v[i] | ||
end | end | ||
else | else | ||
for i = 1, | for i = 1, len(k) do | ||
t[k[i]] = v | t[k[i]] = v | ||
end | end | ||