vimtricks.wiki Concise Vim tricks, one at a time.

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; use copy() first if you want a new list: map(copy(original), lambda)
  • Both v:key and v:val are 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

Next

How do I right-justify a line of text to a specific width using a built-in Vim command?