Skip to content

Instantly share code, notes, and snippets.

@royratcliffe
Last active April 28, 2024 15:42
Show Gist options
  • Save royratcliffe/12d74d27df1d38e2c2350c8a610a1cf8 to your computer and use it in GitHub Desktop.
Save royratcliffe/12d74d27df1d38e2c2350c8a610a1cf8 to your computer and use it in GitHub Desktop.
Unique Lua Pairs
--- Unique pairs.
-- @module uniq
-- @author Roy Ratcliffe <[email protected]>
-- @copyright 2023, 2024
-- @license MIT
local _M = {}
local unpack = table.unpack or unpack -- Lua 5.1 compatibility
--- Answers the next index and unique value.
-- See [Semantics of the Generic `for`](https://www.lua.org/pil/7.2.html) for
-- details.
-- @tparam {{any,...},{[any]=bool}} forinvar For-loop invariant.
-- @tparam int forvar For-loop variant.
-- @treturn int Current index.
-- @treturn any Current unique value.
local function inext(forinvar, forvar)
local values, matched = unpack(forinvar)
local value
repeat
forvar = forvar + 1
value = values[forvar]
if value == nil then return end
until not matched[value]
matched[value] = true
return forvar, value
end
--- Iterates unique values in an array.
-- Skips duplicates. The implementation utilises a table by up-value reference.
-- Unique `pairs` does not make sense. Index-value pairs automatically have the
-- unique index property.
-- @tparam {any,...} Array of any values.
-- @treturn func Iterator function.
-- @treturn {{any,...},{[any]=bool}} Tuple of values and matches.
-- @treturn number Initial array index.
function _M.ipairs(values)
return inext, { values, {} }, 0
end
return _M
describe("uniq", function()
local UNIQ = require "uniq"
it("works", function()
local actual = {}
for index, value in UNIQ.ipairs { "a", "a", 1, 2, 3, 3 } do
table.insert(actual, { index, value })
end
assert.are.same({
{ 1, "a" },
{ 3, 1 },
{ 4, 2 },
{ 5, 3 },
}, actual)
end)
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment