I've tried this but it didn't work

function! Reduce(array, oper, accumInit) abort
  let l:accum = a:accumInit
  for l:item in a:array
    let l:accum = a:oper(l:accum, l:item)

  return l:accum

function! FooBar() abort
  let g:foobar = Reduce(['pit', 'joh', 'dik'], {ac, el -> extend(ac, {[el]:len(el)})}, {})

Error detected while processing function FooBar[1]..Reduce[3]..<lambda>3:
line    1:
E730: using List as a String
E116: Invalid arguments for function extend
  • Vim supports reduce() since 8.2.0878. Vim9 supports [key-expr]: value since 8.2.2015.
    – user938271
    Mar 30, 2021 at 15:48
  • neovim and lua seem to be a future
    – vatosarmat
    Mar 31, 2021 at 15:58

2 Answers 2

  1. In the newest Vim version (not in Neovim yet) reduce() is a builtin.

  2. Dictionary in VimScript can only have String keys (cf. AWK). For this reason, [key]: value notation is not even supported.

  3. Obviously, if all items are strings anyway then you can have {el: len(el)}. Otherwise {string(el): len(el)} might also work for you. But, chances are, you need to re-think your problem completely.


As Matt said, it should be {e: len(e)}.

Also, for efficiency with vimscript language, you should prefer map(), but this will introduce a new parameter in the oper function

call map(copy(a:array), {_, e -> extend(a:accumInit, {e: len(e)})})
return a:accumInit

It could be encapsulated in your namespace#reduce() function though:

call map(copy(a:array), {_, e -> extend(a:oper(a:accumInit, e))})

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.