Calcola rapidamente il totale di una colonna di numeri


15

Sto scrivendo una tabella di markdown che assomiglia a questa:

| 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   |

Sto cercando un modo per calcolare rapidamente il totale della terza colonna e inserirlo nel buffer. La soluzione che ho in mente farebbe uso della modalità blocco visivo (per selezionare tutti i numeri) e forse del registro delle espressioni (per fare la matematica).

Questo sarebbe possibile usando i comandi nativi di Vim? Altrimenti, c'è un plugin che mi può aiutare?


1
Puoi dare un'occhiata a questo articolo: vim.wikia.com/wiki/Using_vim_as_calculator
nobe4

Risposte:


15

Ho scritto un plugin: https://github.com/sk1418/HowMuch che supporta la selezione visiva e esegue calcoli matematici.

Per impostazione predefinita, il plug-in supporta tre motori di valutazione delle espressioni matematiche: Gnu bc, python e vimscript. Puoi fare i calcoli su un determinato o lasciare che il plugin scelga automaticamente uno per te.

Funziona con il tuo esempio in questo modo:

inserisci qui la descrizione dell'immagine

Per i dettagli, leggi il README su github.


Sarebbe utile se includessi i tasti premuti per selezionare, sommare e inserire nella tua risposta.
pdoherty926,

@ pdoherty926 For details please read the README on github.Anche se ho inserito i tasti premuti per questo problema, non vedo quanto possa essere utile, sono solo 3 o 4 combinazioni di tasti. Se la mia sceneggiatura è davvero necessaria per qualcuno, controllerà comunque i dettagli.
Kent,

12

Se non si desidera utilizzare plug-in o passare a uno script bash, è possibile eseguire le operazioni seguenti:

  • c-V {motions} "ay copia colonna in "a
  • :let @a = substitute(@a, 'c-V c-J', '+', 'g') sostituire la colonna newline con +
  • ic-R=c-Raeseguire il sostituito "atramite il registro delle espressioni

In alternativa: rendere riutilizzabile la voce della cronologia delle espressioni per ulteriori somme di colonne

  • ctrl-V {motions} y mettere la colonna nel registro yank ""
  • ictrl-R=eval(substitute(@", '\n', '+', 'g'))

Ripetendo per un'altra colonna:

  • ctrl-V {motion} y (Invariato)
  • ictrl-R=<CR>o se hai fatto qualcos'altro con il registro delle espressioni, scorri la cronologia con il tasto freccia su (o con ctrl-Pse lo hai rimappato):
    ictrl-R=<up>...<up><CR>

1
Per qualche motivo sono riuscito a utilizzare la tua soluzione solo con virgolette doppie "anziché virgolette singole 'sul substitutecomando. Sai se c'è qualche motivo per questo?
vappolinario,

@vappolinario funziona in entrambi i modi, quindi temo di non saperlo, scusa.
Hovercouch,

@Hovercouch Potresti approfondire il terzo passo? Come, esattamente, si potrebbe fare per eseguire la sostituzione attraverso il registro delle espressioni?
pdoherty926,

Che ne dici di creare una mappa: `nnoremap <cs>: s / $ / \ = eval (sostituto (@ 0, '[^ 0-9]', '+', 'g')) / <cr>`
SergioAraujo

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

Spiegazione:

: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

Ho provato una funzione che funziona qui:

" 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>

Usando la mappa sopra inclusa, tutto ciò che devi fare dopo aver caricato la funzione è selezionare i numeri che vuoi sommare e usare <leader>sper riassumere l'area selezionata.

Spiegazione della funzione:

Utilizza l' try/finally/endtryestrazione per acquisire errori.

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

Se vuoi provare questa funzione, procedi come segue: Copia questa funzione nel tuo browser ed esegui questo comando su vim, :@+ questo ti permetterà di usarlo :call SumVis()normalmente.

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

È necessario effettuare una selezione del blocco visivo con ctrl+ v, deselezionare e infine chiamare la funzione. Oppure puoi utilizzare la mappa suggerita che rimuove da sola la selezione prima del calcolo.



5

Fare un plugin o codificarlo in vimscript sembra un po 'pesante. Credo in un vim senza plug-in e in una buona composizione con strumenti esterni.

Ecco un comando di 1 volta, basato su user2571881, che funziona anche se il buffer non è stato salvato.

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

Se si desidera salvare questo comando per un utilizzo futuro, è possibile nominarlo:

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

Funziona con la selezione visiva. Se selezioni alcune righe e vai in modalità comando, vim farà precedere il tuo comando :'<,'>, che è l'intervallo di linee per la selezione visiva. Quindi puoi eseguire:

:'<,'>SumColumn 3

e sommerà solo la terza colonna delle righe selezionate. Per impostazione predefinita, l'intervallo è %, quindi

:SumColumn 3

sommerà la terza colonna di tutte le righe.

EDIT: Se vuoi essere in grado di specificare altri separatori di campi e di default la colonna conteggiata fino all'ultima, puoi coprire il comando bashe gestire gli argomenti con esso, in questo modo:

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

Adesso,

:SumColumn

conterà l'ultima colonna di una tabella con "|" separatori di campo,

:SumColumn 3

conterà la terza colonna di una tabella con "|" separatori di campo e

:SumColumn 3 +

conterà la terza colonna di una tabella con i separatori di campo "+".


Come si può trattare con altri possibili separatori di campo? Solo per rendere la soluzione più generica.
SergioAraujo,

@ user2571881, ho modificato la risposta, dimostrandola.
JoL,

@JoL aggiungendo funzioni come SumColumna vimrc significa che hai semplicemente i tuoi 'plugin' nel tuo vimrc. Spero che tu sia bravo a mantenerlo nel tempo. Per me i plugin forniscono documentazione, separazione in parti significative, sfruttando l'ingegnosità degli altri. Contribuisco a monte che migliora i plugin incredibili che nessuno ha il tempo di creare tutti da soli (tranne tpope). Non usi vim-surround, vim-fuggitivo, vim-easy-align / vim-lion, vim-intaired, vim-commentary, ultisnips o ft-specific come vim-go, vim-rails, vimtex?
Hotschke,

@Hotschke Quando sono arrivato, ho visto la domanda e ho pensato, "beh, basta passare attraverso awk". Ma poi, ho visto che la risposta accettata era "ehi, scarica queste centinaia di plugin LOC e installalo". La terza risposta è stata "ehi, scarica queste migliaia di plugin LOC e installalo". È eccessivo e gonfio. Anche se hai bisogno di sommare le colonne più di una volta nella tua vita, è eccessivo. La mia risposta ha lo scopo di mostrare come puoi farlo in un singolo comando senza plug-in, senza sciocchezze se devi farlo solo una volta, e come puoi fare un semplice comando con parametri al di fuori se devi farlo spesso.
JoL

@Hotschke Per rispondere alla tua domanda, installavo tutti i plugin sotto il sole che sembravano lontanamente fantastici, ma poi il mio vim era incredibilmente lento (leggi "un po 'ritardato" che è intollerabile per un editor). Guardando più nei documenti di VIM, mi sono reso conto che non avevo davvero bisogno dei plugin. Molte delle funzionalità di stock erano abbastanza buone e, per quelle che Vim non aveva, la shell era la strada da percorrere. Fondamentalmente (ignorando le eccezioni fatte), secondo la filosofia Unix, vim è un editor che interagisce bene con altri strumenti del sistema operativo. Credo che sia il modo di utilizzarlo al meglio. Nessun plugin da allora.
JoL

2

Se le colonne sono allineate correttamente, questo può essere fatto con un semplice oneliner.

  1. seleziona prima la colonna in modalità visuale a blocchi come hanno dimostrato altre risposte -> CTRL-V+ sposta il cursore
  2. strappare la selezione con y
  3. tipo: :echo eval(join(split(@", '\_s\+'), '+'))che divide il testo strappato su spazi e nuove linee, ricongiunge l'elemento con +carattere e valuta la stringa.
  4. un altro modo di procedere: sostituire le nuove righe con +e valutare: :echo eval(substitute(@", "\n", '+', 'g'))- eval()è la cosa più vicina a reducenoi.

In caso contrario, dovrai usare altri trucchi per contare i campi. Ad esempio, split(getline('.'), "[ \t|]\\+")può essere utilizzato per dividere le colonne da una riga nell'array. Da lì, diventa semplice come:

  1. seleziona le tue linee in modalità visiva
  2. :echo eval(join(map(getline("'<", "'>"), { -> split(v:val, "[ \t|]\\+")[2] }), '+'))

Per sbarazzarsi dei valori magici (campo numero - 1 e +), può diventare un comando

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

Quale può essere usato con:

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

Nota: qui uso lambda di Vim 7.4.1xxx


1

vmap ++dal plugin vmathdi Damian Conway

  1. Installa il plugin da github (solo 178 sloc) ad es

    $ wget https://raw.githubusercontent.com/thoughtstream/Damian-Conway-s-Vim-Setup/master/plugin/vmath.vim -P ~/.vim/pack/manual/start/damians-tools/plugin
    
  2. Aggiungi la mappatura al tuo vimrc

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

    Tuttavia, suggerirei di usare qualcos'altro, ad es gA

  3. Passa alla terza colonna 2f|e seleziona la colonna in modalità blocco visivo<C-V>G$
  4. Premi ++(o la mappatura scelta)
  5. I risultati sono mostrati e memorizzati nei registri (somma in s)
  6. Inserisci la somma dal registro s, ad es. Con"sp

Per una presentazione di questo plugin vedere il video di YouTube Damian Conway, "More Instantly Better Vim" - OSCON 2013 (a partire dal minuto 29).


1

Strumento cli esterno csvstatda csvkit

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

Breve spiegazione delle opzioni

  • -d DELIMITERDelimitazione del carattere del file CSV di input. QUI |.
  • -H Specificare che il file CSV di input non ha riga di intestazione.
  • -c COLUMNSUn elenco separato da virgole di indici di colonna o nomi da esaminare. Il valore predefinito è tutte le colonne.
  • --sum Emette solo somme.

Questo strumento fornisce anche min, max, media, mediana, stdev (deviazione standard), conta valori univoci, elenco di valori frequenti.

Inserisci nel file con

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

Installazione

Su macOS csvkit è disponibile tramite homebrew e su Debian / Ubuntu e simili con cui può essere installato $ sudo apt install csvkit.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.