LoginSignup
7
7

More than 5 years have passed since last update.

sortあるある

Last updated at Posted at 2014-11-27

欲しい結果はこれじゃない…

0
1
10
2
3
4
5
6
7
8
9

あのRubyの生みの親まつもと ゆきひろさんも言っていました
「こうなるからRubyのバージョンには2桁の番号を付けない」と。

追記(2014/11/29)

:sort nで整数順でソートが出来ました。@thincaさんありがとうございます。Vimステキ:heart:

Vimスクリプトで解決しよう

せっかくスクリプトにするのでついでに小数のソートにも対応しましょう

FSort.vim
command! -nargs=? -range=% -bang FSort :<line1>,<line2>call s:FSort(<bang>0, <q-args>)

function! s:FComp(lhs, rhs)
    let l:lhs = str2float(substitute(a:lhs, s:pat, "", ""))
    let l:rhs = str2float(substitute(a:rhs, s:pat, "", ""))
    return l:lhs == l:rhs ? 0 : l:lhs < l:rhs ? -1 : 1
endfunction

function! s:FCompBang(lhs, rhs)
    return -s:FComp(a:lhs, a:rhs)
endfunction

function! s:FSort(bang, ...) range
    if (a:1 != "")
        let s:pat = matchstr(a:1, '/\@<=.*/\@=')
    else
        let s:pat = '.\{-}\%\(\d\|-\)\@='
    endif

    let lines = []
    for i in range(a:firstline, a:lastline)
        call add(lines, getline(i))
    endfor
    if (a:bang)
        call sort(lines, "s:FCompBang")
    else
        call sort(lines, "s:FComp")
    endif
    for i in range(a:firstline, a:lastline)
        call setline(i, lines[i - a:firstline])
    endfor
endfunction

vim内臓の:sort同様に:FSort!で逆順とか、
:FSort! /\(\(\d\|\.\)\+\s*,\s*\)\{2}/で以下のように
2つ目のカラムまで読み飛ばして小数で逆順ソートなどできます。

1,  0, 2.4 , 2
4,  1, 2.3 , 0
5, 11, 2.1 , 1
0,  0, 1.4 , 0
6,  9, 1.12, 2
3,  0, 1.1 , 1
8,  1, 0.9 , 1
9,  0, 0.1 , 2
6, 10, 0.03, 0

Vim8がリリースされたのでlambdaを使ってみる

command! -nargs=? -range=% -bang FracSort :<line1>,<line2>call s:FracSort(<bang>0, <q-args>)

function! s:FracSort(bang, ...) range
    if (a:1 != "")
        let l:pat = matchstr(a:1, '/\@<=.*/\@=')
    else
        let l:pat = '\v.{-}%(-?%(%(\.%(\d)@=)|\d))@='
    endif

    let lines = []
    for i in range(a:firstline, a:lastline)
        call add(lines, getline(i))
    endfor

    let l:Fn = { x -> str2float(substitute(x, l:pat, "", "")) }

    if (a:bang)
        call sort(lines, { a, b -> l:Fn(a) == l:Fn(b) ? 0 : l:Fn(a) < l:Fn(b) ? 1 : -1 })
    else
        call sort(lines, { a, b -> l:Fn(a) == l:Fn(b) ? 0 : l:Fn(a) < l:Fn(b) ? -1 : 1 })
    endif
    for i in range(a:firstline, a:lastline)
        call setline(i, lines[i - a:firstline])
    endfor
endfunction
7
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7