mirror of
https://github.com/neovim/neovim.git
synced 2025-09-27 05:28:33 +00:00
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:

committed by
Lewis Russell

parent
7a051a4c38
commit
cf9b36f3d9
@@ -2092,6 +2092,35 @@ vim.islist({t}) *vim.islist()*
|
|||||||
See also: ~
|
See also: ~
|
||||||
• |vim.isarray()|
|
• |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()*
|
vim.list_contains({t}, {value}) *vim.list_contains()*
|
||||||
Checks if a list-like table (integer keys without gaps) contains `value`.
|
Checks if a list-like table (integer keys without gaps) contains `value`.
|
||||||
|
|
||||||
|
@@ -227,6 +227,7 @@ LUA
|
|||||||
• |vim.version.intersect()| computes intersection of two version ranges.
|
• |vim.version.intersect()| computes intersection of two version ranges.
|
||||||
• |Iter:take()| and |Iter:skip()| now optionally accept predicates.
|
• |Iter:take()| and |Iter:skip()| now optionally accept predicates.
|
||||||
• Built-in plugin manager |vim.pack|
|
• Built-in plugin manager |vim.pack|
|
||||||
|
• |vim.list.unique()| to deduplicate lists.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
|
|
||||||
|
@@ -11674,6 +11674,8 @@ undotree([{buf}]) *undotree()*
|
|||||||
(`vim.fn.undotree.ret`)
|
(`vim.fn.undotree.ret`)
|
||||||
|
|
||||||
uniq({list} [, {func} [, {dict}]]) *uniq()* *E882*
|
uniq({list} [, {func} [, {dict}]]) *uniq()* *E882*
|
||||||
|
Note: Prefer |vim.list.unique()| in Lua.
|
||||||
|
|
||||||
Remove second and succeeding copies of repeated adjacent
|
Remove second and succeeding copies of repeated adjacent
|
||||||
{list} items in-place. Returns {list}. If you want a list
|
{list} items in-place. Returns {list}. If you want a list
|
||||||
to remain unmodified make a copy first: >vim
|
to remain unmodified make a copy first: >vim
|
||||||
|
2
runtime/lua/vim/_meta/vimfn.lua
generated
2
runtime/lua/vim/_meta/vimfn.lua
generated
@@ -10628,6 +10628,8 @@ function vim.fn.undofile(name) end
|
|||||||
--- @return vim.fn.undotree.ret
|
--- @return vim.fn.undotree.ret
|
||||||
function vim.fn.undotree(buf) end
|
function vim.fn.undotree(buf) end
|
||||||
|
|
||||||
|
--- Note: Prefer |vim.list.unique()| in Lua.
|
||||||
|
---
|
||||||
--- Remove second and succeeding copies of repeated adjacent
|
--- Remove second and succeeding copies of repeated adjacent
|
||||||
--- {list} items in-place. Returns {list}. If you want a list
|
--- {list} items in-place. Returns {list}. If you want a list
|
||||||
--- to remain unmodified make a copy first: >vim
|
--- to remain unmodified make a copy first: >vim
|
||||||
|
@@ -348,6 +348,62 @@ function vim.list_contains(t, value)
|
|||||||
return false
|
return false
|
||||||
end
|
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.
|
--- Checks if a table is empty.
|
||||||
---
|
---
|
||||||
---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
|
---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
|
||||||
|
@@ -12856,6 +12856,8 @@ M.funcs = {
|
|||||||
base = 1,
|
base = 1,
|
||||||
tags = { 'E882' },
|
tags = { 'E882' },
|
||||||
desc = [=[
|
desc = [=[
|
||||||
|
Note: Prefer |vim.list.unique()| in Lua.
|
||||||
|
|
||||||
Remove second and succeeding copies of repeated adjacent
|
Remove second and succeeding copies of repeated adjacent
|
||||||
{list} items in-place. Returns {list}. If you want a list
|
{list} items in-place. Returns {list}. If you want a list
|
||||||
to remain unmodified make a copy first: >vim
|
to remain unmodified make a copy first: >vim
|
||||||
|
@@ -1260,6 +1260,28 @@ describe('lua stdlib', function()
|
|||||||
eq({ 2 }, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]])
|
eq({ 2 }, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('vim.list.unique', function()
|
||||||
|
eq({ 1, 2, 3, 4, 5 }, vim.list.unique({ 1, 2, 2, 3, 4, 4, 5 }))
|
||||||
|
eq({ 1, 2, 3, 4, 5 }, vim.list.unique({ 1, 2, 3, 4, 4, 5, 1, 2, 3, 2, 1, 2, 3, 4, 5 }))
|
||||||
|
eq({ 1, 2, 3, 4, 5, field = 1 }, vim.list.unique({ 1, 2, 2, 3, 4, 4, 5, field = 1 }))
|
||||||
|
|
||||||
|
-- Not properly defined, but test anyway
|
||||||
|
-- luajit evaluates #t as 7, whereas Lua 5.1 evaluates it as 12
|
||||||
|
local r = vim.list.unique({ 1, 2, 2, 3, 4, 4, 5, nil, 6, 6, 7, 7 })
|
||||||
|
if jit then
|
||||||
|
eq({ 1, 2, 3, 4, 5, nil, nil, nil, 6, 6, 7, 7 }, r)
|
||||||
|
else
|
||||||
|
eq({ 1, 2, 3, 4, 5, nil, 6, 7 }, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
eq(
|
||||||
|
{ { 1 }, { 2 }, { 3 } },
|
||||||
|
vim.list.unique({ { 1 }, { 1 }, { 2 }, { 2 }, { 3 }, { 3 } }, function(x)
|
||||||
|
return x[1]
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
it('vim.tbl_add_reverse_lookup', function()
|
it('vim.tbl_add_reverse_lookup', function()
|
||||||
eq(
|
eq(
|
||||||
true,
|
true,
|
||||||
|
Reference in New Issue
Block a user