数字の列の合計をすばやく計算する


15

次のようなマークダウンテーブルを書き留めています。

| 13/05/15 | 09:30-16:00 |  6.5 |
| 14/05/15 | 10:00-16:30 |  6.5 |
| 16/05/15 | 15:30-01:00 |  9.5 |
| 21/05/15 | 09:00-16:30 |  7.5 |
| 22/05/15 | 08:30-17:00 |  8.5 |
| 28/05/15 | 09:30-15:30 |  6   |
| 02/06/15 | 09:00-20:00 | 11   |
| 03/06/15 | 08:30-22:30 | 14   |

3番目の列の合計をすばやく計算し、バッファーに挿入する方法を探しています。私が念頭に置いている解決策は、(すべての数字を選択するための)ビジュアルブロックモードと(計算を行うための)式レジスタを使用することです。

これはネイティブのVimコマンドを使用して可能ですか?そうでない場合、私を助けることができるプラグインはありますか?


1
この記事をご覧
nobe4

回答:


15

プラグインを作成しました:https : //github.com/sk1418/HowMuch は視覚的な選択をサポートし、数学計算を行います。

デフォルトでは、プラグインはGnu bc、python、vimscriptの3つの数式評価エンジンをサポートしています。特定の計算を行うか、プラグインに自動的に選択させることができます。

この例のように動作します:

ここに画像の説明を入力してください

詳細については、githubのREADMEをお読みください。


回答に選択、合計、挿入に必要なキーストロークを含めると便利です。
pdoherty926

@ pdoherty926 For details please read the README on github.この問題のために私が押したキーストロークをここに置いたとしても、それがどれほど役立つかわかりません。それはたった3つか4つのキーの組み合わせです。私のスクリプトが誰かに本当に必要な場合、彼/彼女はとにかく詳細をチェックします。
ケント

11

プラグインを使用したり、bashスクリプトにドロップしたりしたくない場合は、次のようなことができます。

  • c-V {motions} "ay 列をコピーする "a
  • :let @a = substitute(@a, 'c-V c-J', '+', 'g') 列の改行を次のように置き換えます +
  • ic-R=c-Ra"a式レジスタを介して置換を実行します

または、列のさらなる合計に対して式履歴エントリを再利用可能にします

  • ctrl-V {motions} y ヤンクレジスタに列を入れます ""
  • ictrl-R=eval(substitute(@", '\n', '+', 'g'))

別の列で繰り返す:

  • ctrl-V {motion} y (変更なし)
  • ictrl-R=<CR>または、式レジスタで何か他のことをした場合は、上矢印キーを使用して(またはctrl-P再マップした場合は)履歴を循環します。
    ictrl-R=<up>...<up><CR>

1
何らかの理由で、コマンドで"単一引用符'ではなく二重引用符でソリューションを使用することができましたsubstitute。その理由があるかどうか知っていますか?
vappolinario

@vappolinarioそれは私のために両方の方法で動作するので、私はわからないので、申し訳ありません。
ホバーカウチ

@Hovercouch 3番目のステップについて詳しく教えてください。正確に、式レジスタを介して置換を実行するにはどうすればよいでしょうか?
pdoherty926

マップの作成方法: `nnoremap <cs>:s / $ / \ = eval(substitute(@ 0、 '[^ 0-9]'、 '+'、 'g'))/ <cr>`
SergioAraujo

9
:r!awk '{sum+=$6} END {print "Total: "sum}' %

説明:

:r ........... read (put result in this file)
! ............ external command
awk .......... external tool
{sum+=$6} .... sixth field (awk considers spaces as field separator)
END .......... at the end
{print "Total: "sum} --> string "Total: " plus your result
% ............ current file

私はここで機能する機能を試しています:

" This function requires you select the numbers
fun! SumVis()
    try
        let l:a_save = @a
        norm! gv"ay
        let @a = substitute(@a,'[^0-9. ]','+','g')
        exec "norm! '>o"
        exec "norm! iTotal \<c-r>=\<c-r>a\<cr>"
     finally
        let @a = l:a_save
     endtry
endfun
vnoremap <leader>s :<C-u>call SumVis()<cr>

含まれている上記のマップを使用して、関数をロードした後に行う必要があるのは、合計したい数字を選択<leader>sし、選択したエリアを合計することだけです。

機能説明:

try/finally/endtryextructureを使用してエラーをキャプチャします。

let l:a_save = @a .......... if whe have register 'a' we save it temporarelly
norm! gv"a  ................................... gv --> reselects and captures selection to 'register a'
let @a = substitute(@a,'[^0-9. ]','+','g') .... removes all but numbers, dots and spaces from 'register a' and puts '+' among the numbers
exec "norm! '>o"  ............................. opens new line bellow selection. see :h '>
exec "norm! iTotal: \<c-r>=\<c-r>a\<cr>" ...... insert "Total: " plus 'expression register result
let @a = l:a_save ............................. restores original 'a' register content

この機能を試してみたい場合は、次の操作を行ってください。ブラウザでこの機能をコピーし、vimで:@+ このコマンドを実行すると、:call SumVis()正常に使用できるようになります。

:@+ ......... loads `+` register making the function avaiable

ctrl+ vで視覚的なブロック選択を行い、選択を解除し、最後に関数を呼び出す必要があります。または、提案されたマップを使用して、計算する前にそれ自体で選択を削除することができます。



5

プラグインを作成するか、vimscriptでこれをコーディングするのは少し重いようです。プラグインフリーのvimと、外部ツールを備えた優れた構成を信じています。

以下は、user257188​​1に基づく1回限りのコマンドで、バッファが保存されていなくても機能します。

:%!awk -F '|' '{print; sum+=$4}; END {print "Total: "sum}'

将来使用するためにこのコマンドを保存する場合は、名前を付けることができます。

:command! -range=% -nargs=1 SumColumn <line1>,<line2>!awk -F '|' '{print; sum+=$('<args>' + 1)} END {print "Total: "sum}'

視覚的な選択で動作します。いくつかの行を選択してコマンドモードに入ると、vimはコマンドの先頭にを付けます。:'<,'>これは、視覚的な選択の行範囲です。だからあなたは実行することができます:

:'<,'>SumColumn 3

また、選択した行の3列目のみを合計します。デフォルトでは、範囲は%ですので、

:SumColumn 3

すべての行の3列目を合計します。

編集:他のフィールドセパレータを指定し、デフォルトで最後のカラムにカウントされるようにしたい場合は、次のようにコマンドをカバーしbashて引数を処理できます。

:command! -range=% -nargs=* SumColumn <line1>,<line2>!bash -c 'awk -F ${2:-|} "{print; sum+=\$(${1:-NF - 2} + 1)} END {print \"Total: \"sum}"' sumcolumn <args>

さて、

:SumColumn

テーブルの最後の列を「|」でカウントします フィールドセパレータ、

:SumColumn 3

「|」でテーブルの3列目を数えます フィールドセパレーター、および

:SumColumn 3 +

「+」フィールド区切り文字でテーブルの3番目の列をカウントします。


他の可能性のあるフィールドセパレータをどのように扱うことができますか?ソリューションをより一般的にするためだけに。
SergioAraujo

@ user257188​​1、答えを編集して、それを示しました。
JOL

@JoL SumColumnがvimrcのような関数を追加することは、vimrcに「プラグイン」があるだけであることを意味します。うまくいけば、あなたはこれを時間とともに維持するのが得意です。私にとってプラグインは、ドキュメントを提供し、意味のある部分に分離し、他の工夫を活用します。私はアップストリームに貢献し、驚くべきプラグインを改善します。誰もがそれらをすべて自分で作成する時間はありません(tpopeを除く)。vim-surround、vim-fugitive、vim-easy-align / vim-lion、vim-impaired、vim-commentary、ultisnips、またはvim-go、vim-rails、vimtexなどのft固有のものを使用しませんか?
-Hotschke

@Hotschke私がここに着いたとき、私は質問を見て、「まあ、awkをパイプでつないでください」しかし、その後、受け入れられた答えは、「ねえ、この何百ものLOCプラグインをダウンロードしてインストールしてください」でした。3番目の答えは、「ねえ、何千ものLOCプラグインをダウンロードしてインストールしてください」でした。それは行き過ぎで肥大化しています。人生で複数回列を合計する必要があったとしても、それはやり過ぎです。私の答えは、これを1回だけ行う必要がある場合に単一のno-plugins、no-nonsenseコマンドでこれを行う方法、およびこれを行う必要がある場合にパラメータを使用して簡単なコマンドを作成する方法を示すことを意味しますしばしば。
-JoL

@Hotschkeあなたの質問に答えるために、私はすべてのプラグインをリモートで涼しく見える太陽の下でインストールしていましたが、私のvimは信じられないほど遅かったです(エディタには耐えられない「少し遅れる」を読んでください)。vim docsをさらに調べると、プラグインは本当に必要ないことがわかりました。ストック機能の多くは十分に優れていたので、vimにはなかった機能としてはシェルが最適です。基本的に(作成された例外を無視して)、Unixの哲学に従って、vimは他のOSツールと相互運用性の高いエディターです。それがそれを最大限に活用する方法だと思います。以降、プラグインはありません。
-JoL

2

列が適切に配置されている場合、これは簡単なワンライナーで実行できます。

  1. 他の回答が示すように、まずブロック単位の視覚モードで列を選択します-> CTRL-V+カーソルを移動します
  2. 選択範囲をヤンクします y
  3. type::echo eval(join(split(@", '\_s\+'), '+'))スペースと改行でヤンクされたテキストを分割し、要素を+文字で再結合し、文字列を評価します。
  4. 続行する別の方法:改行を置き換えて+評価する::echo eval(substitute(@", "\n", '+', 'g'))- eval()が最も近いものreduceです。

そうでない場合は、他のトリックを使用してフィールドをカウントする必要があります。たとえばsplit(getline('.'), "[ \t|]\\+")、配列内の行から列を分割するために使用できます。そこから、次のように簡単になります。

  1. 視覚モードで線を選択します
  2. :echo eval(join(map(getline("'<", "'>"), { -> split(v:val, "[ \t|]\\+")[2] }), '+'))

魔法の値(フィールド番号-1、および+)を取り除くために、コマンドになることができます

:command! -range=% -nargs=+ OnField 
    \ echo { field, what -> eval(join(map(getline(<line1>, <line2>), { -> split(v:val, "[ \t|]\\+")[field-1] }), what))}(<f-args>)

以下で使用できます:

:OnField  3 +
:2,5OnField  3 +
:'<,'>Onfield 3 *   " after line-wise selection
....

注:ここでは、Vim 7.4.1xxxのラムダを使用します


1

Damian Conwayによる++プラグインからのvmapvmath

  1. githubからプラグインをインストールする(178 slocのみ)例

    $ wget https://raw.githubusercontent.com/thoughtstream/Damian-Conway-s-Vim-Setup/master/plugin/vmath.vim -P ~/.vim/pack/manual/start/damians-tools/plugin
    
  2. vimrcにマッピングを追加します

    vmap <silent><expr>  ++  VMATH_YankAndAnalyse()
    

    ただし、他の何かを使用することをお勧めします、例えば gA

  3. 3番目の列に移動し、2f|視覚ブロックモードで列を選択します<C-V>G$
  4. ++(または選択したマッピング)を押します
  5. 結果が表示され、レジスタに保存されます(合計s
  6. registerから合計を挿入しますs。たとえば"sp

このプラグインのプレゼンテーションについては、YouTubeビデオのDamian Conwayの「More Instantly Better Vim」-OSCON 2013(29分から開始)を参照してください。


1

外部のCLIツールcsvstatからcsvkit

:!csvstat -d '|' -H -c 4 --sum %
69.5

オプションの簡単な説明

  • -d DELIMITER入力CSVファイルの区切り文字。こちら|
  • -H 入力CSVファイルにヘッダー行がないことを指定します。
  • -c COLUMNS検査する列インデックスまたは名前のコンマ区切りリスト。デフォルトはすべての列です。
  • --sum 合計のみを出力します。

このツールは、最小値、最大値、平均値、中央値、標準偏差(標準偏差)、一意の値のカウント、頻繁な値のリストも提供します。

にファイルに挿入

<C-r>=system("csvstat -d '|' -H -c 4 --sum FILENAME 2> /dev/null")  

設置

macOSではcsvkitはhomebrew経由で、Debian / Ubuntuでは同様の方法でインストールできます$ sudo apt install csvkit

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.