Calculez rapidement le total d'une colonne de nombres

15

J'écris une table de démarque qui ressemble à ceci:

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

Je cherche un moyen de calculer rapidement le total de la troisième colonne et de l'insérer dans le tampon. La solution que j'ai en tête consisterait à utiliser le mode bloc visuel (pour sélectionner tous les nombres) et peut-être le registre d'expression (pour faire le calcul).

Serait-ce possible en utilisant les commandes natives de Vim? Sinon, existe-t-il un plugin qui peut m'aider?

zool
la source
1
Vous pouvez consulter cet article: vim.wikia.com/wiki/Using_vim_as_calculator
nobe4

Réponses:

15

J'ai écrit un plugin: https://github.com/sk1418/HowMuch qui prend en charge la sélection visuelle et effectue des calculs mathématiques.

Par défaut, le plugin prend en charge trois moteurs d'évaluation d'expressions mathématiques: Gnu bc, python et vimscript. Vous pouvez faire les calculs sur un certain ou laisser le plugin en choisir automatiquement un pour vous.

Cela fonctionne avec votre exemple comme ceci:

entrez la description de l'image ici

Pour plus de détails, veuillez lire le fichier README sur github.

Kent
la source
Il serait utile d'inclure les touches nécessaires pour sélectionner, additionner et insérer dans votre réponse.
pdoherty926
@ pdoherty926 For details please read the README on github.Même si je mets ici les touches sur lesquelles j'ai appuyé pour ce problème, je ne vois pas à quel point cela pourrait être utile, il ne s'agit que de 3 ou 4 combinaisons de touches. Si mon script est vraiment nécessaire à quelqu'un, il vérifiera quand même les détails.
Kent
12

Si vous ne voulez pas utiliser de plugins ou passer à un script bash, vous pouvez faire quelque chose comme ceci:

  • c-V {motions} "ay copier la colonne dans "a
  • :let @a = substitute(@a, 'c-V c-J', '+', 'g') remplacer les nouvelles lignes de colonne par +
  • ic-R=c-Raexécuter le remplacé "avia le registre d'expression

Alternativement: rendre l'entrée de l'historique des expressions réutilisable pour d'autres sommes de colonnes

  • ctrl-V {motions} y mettre la colonne dans le registre yank ""
  • ictrl-R=eval(substitute(@", '\n', '+', 'g'))

Répétition pour une autre colonne:

  • ctrl-V {motion} y (inchangé)
  • ictrl-R=<CR>ou si vous avez fait autre chose avec le registre d'expressions, parcourez l'historique avec la touche fléchée vers le haut (ou avec ctrl-Psi vous l'avez remappé):
    ictrl-R=<up>...<up><CR>
Hovercouch
la source
1
Pour une raison quelconque, je n'ai réussi à utiliser votre solution qu'avec des guillemets doubles "au lieu de guillemets simples 'sur la substitutecommande. Savez-vous s'il y a une raison à cela?
vappolinario
@vappolinario ça marche dans les deux sens pour moi, donc j'ai peur de ne pas savoir, désolé.
Hovercouch
@Hovercouch Pourriez-vous développer la troisième étape? Comment, exactement, procéderait-on pour exécuter le remplacement via le registre d'expression?
pdoherty926
Que diriez-vous de faire une carte: `nnoremap <cs>: s / $ / \ = eval (substitut (@ 0, '[^ 0-9]', '+', 'g')) / <cr>`
SergioAraujo
9
:r!awk '{sum+=$6} END {print "Total: "sum}' %

Explication:

: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

J'ai essayé une fonction qui fonctionne ici:

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

En utilisant la carte ci-dessus incluse, tout ce que vous avez à faire après le chargement dans la fonction est de sélectionner les nombres que vous souhaitez additionner et utiliser <leader>spour additionner la zone sélectionnée.

Explication de la fonction:

Il utilise l' try/finally/endtryextructure pour capturer les erreurs.

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

Si vous voulez essayer cette fonction, procédez comme suit: Copiez cette fonction dans votre navigateur et exécutez cette commande sur vim :@+ cela vous permettra de l'utiliser :call SumVis()normalement.

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

Il vous faut faire une sélection de bloc visuelle avec ctrl+ v, désélectionner et enfin appeler la fonction. Ou vous pouvez utiliser la carte suggérée qui supprime d'elle-même la sélection avant le calcul.

SergioAraujo
la source
7

Mon plugin csv le permet. Utilisez la :SumColcommande et assurez-vous de lire la documentation.

Christian Brabandt
la source
5

Faire un plugin ou le coder en vimscript semble un peu lourd. Je crois en un vim sans plugin et une bonne composition avec des outils externes.

Voici une commande unique, basée sur celle de user2571881, qui fonctionne même si le tampon n'a pas été enregistré.

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

Si vous souhaitez enregistrer cette commande pour une utilisation future, vous pouvez la nommer:

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

Cela fonctionne avec la sélection visuelle. Si vous sélectionnez quelques lignes et passez en mode commande, vim préfixera votre commande :'<,'>, qui est la plage de lignes pour la sélection visuelle. Vous pouvez donc exécuter:

:'<,'>SumColumn 3

et il additionnera seulement la 3ème colonne des lignes sélectionnées. Par défaut, la plage est %, donc

:SumColumn 3

additionnera la 3ème colonne de toutes les lignes.

EDIT: Si vous souhaitez pouvoir spécifier d'autres séparateurs de champs et par défaut la colonne comptée jusqu'à la dernière, vous pouvez couvrir la commande bashet gérer les arguments avec, comme ceci:

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

Maintenant,

:SumColumn

comptera la dernière colonne d'une table avec "|" séparateurs de champ,

:SumColumn 3

comptera la 3ème colonne d'un tableau avec "|" séparateurs de champ, et

:SumColumn 3 +

comptera la 3ème colonne d'un tableau avec des séparateurs de champ "+".

JoL
la source
Comment gérer les autres séparateurs de champs possibles? Juste pour rendre la solution plus générique.
SergioAraujo
@ user2571881, j'ai édité la réponse, montrant cela.
JoL
@JoL ajouter des fonctions comme SumColumnvimrc signifie que vous avez simplement vos «plugins» dans votre vimrc. J'espère que vous réussissez à maintenir cela avec le temps. Pour moi, les plugins fournissent la documentation, la séparation en parties significatives, tirant parti de l'ingéniosité des autres. Je contribue à l'amont qui améliore des plugins incroyables que personne n'a le temps de créer tous par eux-mêmes (sauf tpope). N'utilisez-vous pas vim-surround, vim-fugitive, vim-easy-align / vim-lion, vim-unimpaired, vim-commentary, ultisnips ou spécifiques à ft tels que vim-go, vim-rails, vimtex?
Hotschke
@Hotschke Quand je suis arrivé ici, j'ai vu la question et j'ai pensé: "Eh bien, il suffit de passer à travers awk." Mais ensuite, j'ai vu que la réponse acceptée était: "Hé, téléchargez ces centaines de plugins LOC et installez-les." La troisième réponse était: "Hé, téléchargez ces milliers de plugins LOC et installez-les." C'est exagéré et ballonnement. Même si vous avez dû additionner des colonnes plus d'une fois dans votre vie, c'est exagéré. Ma réponse est destinée à montrer comment vous pouvez le faire dans une seule commande no plugins, no-nonsense si vous n'avez besoin de le faire qu'une seule fois, et comment vous pouvez en faire une commande simple avec des paramètres si vous devez le faire souvent.
JoL
@Hotschke Pour répondre à votre question, j'avais l'habitude d'installer tous les plugins sous le soleil qui avaient l'air cool à distance, mais mon vim était incroyablement lent (lire "un peu décalé" ce qui est intolérable pour un éditeur). En examinant davantage les documents vim, j'ai réalisé que je n'avais pas vraiment besoin des plugins. La plupart des caractéristiques du stock étaient assez bonnes et, pour ceux que vim n'avait pas, la coquille était la voie à suivre. Fondamentalement (en ignorant les exceptions, il est fait), selon la philosophie Unix, vim est un éditeur qui interagit bien avec les autres outils du système d'exploitation. Je pense que c'est la meilleure façon de l'utiliser. Aucun plugin depuis.
JoL
2

Si les colonnes sont correctement alignées, cela peut être fait avec un simple oneliner.

  1. sélectionnez d'abord la colonne en mode visuel bloc par bloc, comme l'ont démontré d'autres réponses -> CTRL-V+ déplacez le curseur
  2. arracher la sélection avec y
  3. type: :echo eval(join(split(@", '\_s\+'), '+'))qui fractionne le texte tiré sur les espaces et les nouvelles lignes, rejoint l'élément avec du +caractère et évalue la chaîne.
  4. une autre façon de procéder: remplacer les sauts de ligne par +et évaluer: :echo eval(substitute(@", "\n", '+', 'g'))- eval()est la chose la plus proche de reducenous.

Sinon, vous devrez utiliser d'autres astuces pour compter les champs. Par exemple, split(getline('.'), "[ \t|]\\+")peut être utilisé pour diviser les colonnes d'une ligne de votre tableau. À partir de là, cela devient aussi simple que:

  1. sélectionnez vos lignes en mode visuel
  2. :echo eval(join(map(getline("'<", "'>"), { -> split(v:val, "[ \t|]\\+")[2] }), '+'))

Afin de se débarrasser des valeurs magiques (numéro de champ - 1, et +), cela peut devenir une commande

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

Qui peut être utilisé avec:

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

Remarque: ici, j'utilise des lambdas de Vim 7.4.1xxx

Luc Hermitte
la source
1

vmap ++du plugin vmathpar Damian Conway

  1. Installer le plugin depuis github (seulement 178 sloc) par exemple

    $ wget https://raw.githubusercontent.com/thoughtstream/Damian-Conway-s-Vim-Setup/master/plugin/vmath.vim -P ~/.vim/pack/manual/start/damians-tools/plugin
    
  2. Ajoutez un mappage à votre vimrc

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

    Cependant, je suggérerais d'utiliser autre chose, par exemple gA

  3. Passez à la troisième colonne 2f|et sélectionnez la colonne en mode bloc visuel<C-V>G$
  4. Appuyez sur ++(ou sur la cartographie choisie)
  5. Les résultats sont affichés et stockés dans des registres (somme en s)
  6. Insérez la somme du registre s, par exemple avec"sp

Pour une présentation de ce plugin, voir la vidéo YouTube Damian Conway, "More Instantly Better Vim" - OSCON 2013 (à partir de la minute 29).

Hotschke
la source
1

Outil cli externe csvstatde csvkit

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

Brève explication des options

  • -d DELIMITERDélimitation du caractère du fichier CSV d'entrée. Ici |.
  • -H Spécifiez que le fichier CSV d'entrée n'a pas de ligne d'en-tête.
  • -c COLUMNSUne liste séparée par des virgules d'indices ou de noms de colonnes à examiner. Par défaut à toutes les colonnes.
  • --sum Uniquement les sommes de sortie.

Cet outil fournit également les valeurs min, max, moyenne, médiane, stdev (écart-type), le nombre de valeurs uniques, la liste des valeurs fréquentes.

Insérer dans le fichier avec

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

Installation

Sur macOS csvkit est disponible via homebrew et sur Debian / Ubuntu et similaire, il peut être installé avec $ sudo apt install csvkit.

Hotschke
la source