Matthias Braun
Matthias Braun

Reputation: 34373

Sort numbers in vimscript

Experimenting with vimscript and reading the wonderful Learn Vimscript the Hard Way (LVTHW), I realized that Vim wasn't sorting numbers the way I wanted it to.

For example this function from LVTHW

function! Sorted(l)
    let new_list = deepcopy(a:l)
    call sort(new_list)
    return new_list
endfunction

surprised me when I called it with Sorted([3, 1, 11, 2]):

It returned [1, 11, 2, 3].

I think Vim sorts those numbers in alphabetical order. But I'd expect the function to return the numbers in natural order: [1, 2, 3, 11]

How can I convince Vim (7.4) to do that?

Upvotes: 1

Views: 791

Answers (2)

Kent
Kent

Reputation: 195169

if you've read the help doc of sort() function, you 'll see that you can give a n to {func} parameter to let sort do numerical sorting:

example:

:echo sort([3,1,11,2],'n')
[1, 2, 3, 11]

Upvotes: 1

Matthias Braun
Matthias Braun

Reputation: 34373

The trick is to pass Vim's sort a comparator function, which in my case I called NaturalOrder.

" Sorts numbers in ascending order.
" Examples:
" [2, 3, 1, 11, 2] --> [1, 2, 2, 3, 11]
" ['2', '1', '10','-1'] --> [-1, 1, 2, 10]
function! Sorted(list)
  " Make sure the list consists of numbers (and not strings)
  " This also ensures that the original list is not modified
  let nrs= ToNrs(a:list)
  let sortedList = sort(nrs, "NaturalOrder")
  echo sortedList
  return sortedList
endfunction

" Comparator function for natural ordering of numbers
function! NaturalOrder(firstNr, secondNr)
  if a:firstNr < a:secondNr
    return -1
  elseif a:firstNr > a:secondNr
    return 1
  else 
    return 0
  endif
endfunction

" Coerces every element of a list to a number. Returns a new list without
" modifying the original list.
function! ToNrs(list)
  let nrs = []
  for elem in a:list
    let nr = 0 + elem
    call add(nrs, nr)
  endfor
  return nrs
endfunction

Upvotes: 0

Related Questions