feat(lua): add vim.list.unique()

Problem:
No way to deduplicate values in a list in-place

Solution:
Add `vim.list.unique()`
This commit is contained in:
Lewis Russell
2025-07-25 15:12:23 +01:00
committed by Lewis Russell
parent 7a051a4c38
commit cf9b36f3d9
7 changed files with 114 additions and 0 deletions

View File

@@ -2092,6 +2092,35 @@ vim.islist({t}) *vim.islist()*
See also: ~
• |vim.isarray()|
vim.list.unique({t}, {key}) *vim.list.unique()*
Removes duplicate values from a list-like table in-place.
Only the first occurrence of each value is kept. The operation is
performed in-place and the input table is modified.
Accepts an optional `hash` argument that if provided is called for each
value in the list to compute a hash key for uniqueness comparison. This is
useful for deduplicating table values or complex objects.
Example: >lua
local t = {1, 2, 2, 3, 1}
vim.list.unique(t)
-- t is now {1, 2, 3}
local t = { {id=1}, {id=2}, {id=1} }
vim.list.unique(t, function(x) return x.id end)
-- t is now { {id=1}, {id=2} }
<
Parameters: ~
• {t} (`any[]`)
• {key} (`fun(x: T): any??`) Optional hash function to determine
uniqueness of values
Return: ~
(`any[]`) The deduplicated list
vim.list_contains({t}, {value}) *vim.list_contains()*
Checks if a list-like table (integer keys without gaps) contains `value`.

View File

@@ -227,6 +227,7 @@ LUA
• |vim.version.intersect()| computes intersection of two version ranges.
• |Iter:take()| and |Iter:skip()| now optionally accept predicates.
• Built-in plugin manager |vim.pack|
• |vim.list.unique()| to deduplicate lists.
OPTIONS

View File

@@ -11674,6 +11674,8 @@ undotree([{buf}]) *undotree()*
(`vim.fn.undotree.ret`)
uniq({list} [, {func} [, {dict}]]) *uniq()* *E882*
Note: Prefer |vim.list.unique()| in Lua.
Remove second and succeeding copies of repeated adjacent
{list} items in-place. Returns {list}. If you want a list
to remain unmodified make a copy first: >vim

View File

@@ -10628,6 +10628,8 @@ function vim.fn.undofile(name) end
--- @return vim.fn.undotree.ret
function vim.fn.undotree(buf) end
--- Note: Prefer |vim.list.unique()| in Lua.
---
--- Remove second and succeeding copies of repeated adjacent
--- {list} items in-place. Returns {list}. If you want a list
--- to remain unmodified make a copy first: >vim

View File

@@ -348,6 +348,62 @@ function vim.list_contains(t, value)
return false
end
vim.list = {}
--- Removes duplicate values from a list-like table in-place.
---
--- Only the first occurrence of each value is kept.
--- The operation is performed in-place and the input table is modified.
---
--- Accepts an optional `hash` argument that if provided is called for each
--- value in the list to compute a hash key for uniqueness comparison.
--- This is useful for deduplicating table values or complex objects.
---
--- Example:
--- ```lua
---
--- local t = {1, 2, 2, 3, 1}
--- vim.list.unique(t)
--- -- t is now {1, 2, 3}
---
--- local t = { {id=1}, {id=2}, {id=1} }
--- vim.list.unique(t, function(x) return x.id end)
--- -- t is now { {id=1}, {id=2} }
--- ```
---
--- @generic T
--- @param t T[]
--- @param key? fun(x: T): any? Optional hash function to determine uniqueness of values
--- @return T[] : The deduplicated list
function vim.list.unique(t, key)
vim.validate('t', t, 'table')
local seen = {} --- @type table<any,boolean>
local finish = #t
key = key or function(a)
return a
end
local j = 1
for i = 1, finish do
local v = t[i]
local vh = key(v)
if not seen[vh] then
t[j] = v
if vh ~= nil then
seen[vh] = true
end
j = j + 1
end
end
for i = j, finish do
t[i] = nil
end
return t
end
--- Checks if a table is empty.
---
---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua