How do I transform or filter a list inline using Vimscript lambdas with map() and filter()?
Answer
map() and filter() with lambdas
Explanation
Vim 8 introduced lambda expressions with the syntax {args -> expr}, enabling concise inline list transformations. Combined with map() and filter(), this replaces verbose for loops with functional-style one-liners — a significant improvement for Vimscript functions that process buffer lines or arbitrary lists.
How it works
A lambda is an anonymous function written as:
{argument_list -> return_expression}
map() transforms every element of a list in-place; the lambda receives the index (v:key) and value (v:val) as arguments. filter() removes elements for which the lambda returns zero.
Example
Collect all TODO lines from the buffer and print them:
:let todos = filter(getline(1, '$'), {_, v -> v =~# 'TODO'})
:echo todos
Convert a list of words to uppercase:
:let words = ['hello', 'world']
:call map(words, {_, v -> toupper(v)})
:echo words " ['HELLO', 'WORLD']
Extract just line numbers of matching lines (using range()):
:let lnums = filter(range(1, line('$')), {_, l -> getline(l) =~# 'FIXME'})
Tips
map()modifies the list in-place and returns it; usecopy()first if you want a new list:map(copy(original), lambda)- Both
v:keyandv:valare available inside the lambda body as implicit variables; the named parameters (_,v) shadow them - Use
sort(list, {a, b -> a - b})for custom numeric sort using the same lambda syntax - Lambdas are closures: they capture variables from the enclosing scope
- In Neovim with Vim9script, the syntax is more compact with typed arguments