Быстро рассчитать сумму столбца чисел

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   |

Я ищу способ быстро рассчитать сумму третьего столбца и вставить его в буфер. Решение, которое я имею в виду, будет использовать режим визуального блока (для выбора всех чисел) и, возможно, регистр выражений (для вычисления).

Возможно ли это с помощью собственных команд Vim? Если нет, есть ли плагин, который может мне помочь?

Зоол
источник
1
Вы можете взглянуть на эту статью: vim.wikia.com/wiki/Using_vim_as_calculator
nobe4

Ответы:

15

Я написал плагин: https://github.com/sk1418/HowMuch, который поддерживает визуальный выбор и выполняет математические вычисления.

По умолчанию плагин поддерживает три механизма оценки математических выражений: Gnu bc, python и vimscript. Вы можете сделать расчеты для определенного или позволить плагину автоматически выбрать один для вас.

Это работает с вашим примером следующим образом:

введите описание изображения здесь

Для получения подробной информации, пожалуйста, прочитайте README на github.

Кент
источник
Было бы полезно, если бы вы включили нажатия клавиш, необходимые для выбора, суммирования и вставки в ваш ответ.
pdoherty926
@ pdoherty926 For details please read the README on github.Даже если я нажимаю здесь нажатия клавиш для решения этой проблемы, я не понимаю, насколько это может быть полезно, это всего лишь 3 или 4 комбинации клавиш. Если мой сценарий действительно кому-то нужен, он все равно проверит детали.
Кент,
12

Если вы не хотите использовать плагины или перейти на скрипт 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>
Hovercouch
источник
1
По какой-то причине мне удалось использовать ваше решение только с двойными кавычками "вместо одинарных кавычек 'в substituteкоманде. Знаете ли вы, есть ли причина для этого?
Вапполинарио
@vappolinario это работает для меня в обоих направлениях, так что, боюсь, я не знаю, извините.
Hovercouch
@ Hovercouch Не могли бы вы уточнить третий шаг? Как именно можно выполнить замену через регистр выражений?
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/endtryэкструдер для захвата ошибок.

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, отменить выбор и, наконец, вызвать функцию. Или вы можете использовать предложенную карту, которая сама по себе удаляет выбор перед расчетом.

SergioAraujo
источник
7

Мой плагин CSV позволяет это. Используйте :SumColкоманду и обязательно прочитайте документацию.

Кристиан Брабандт
источник
5

Создание плагина или кодирование этого в vimscript кажется немного тяжелым. Я верю в vim без плагинов и хорошую композицию с внешними инструментами.

Вот одноразовая команда, основанная на user2571881, которая работает, даже если буфер не был сохранен.

:%!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
@ user2571881, я отредактировал ответ, показывая это.
JoL
@JoL добавление функций, подобных SumColumnvimrc, означает, что у вас просто есть «плагины» в вашем vimrc. Надеюсь, вы хорошо поддерживаете это со временем. Для меня плагины обеспечивают документацию, разделение на значимые части, используя преимущества других изобретательности. Я делаю вклад в апстрим, который улучшает удивительные плагины, которые никто не имеет времени, чтобы создать их все самостоятельно (кроме tpope). Разве вы не используете vim -round, vim-fugitive, vim-easy-align / vim-lion, vim-unimpaired, vim-commentary, ultisnips или ft-специфичные, такие как vim-go, vim-rails, vimtex?
Хотчке
@Hotschke Когда я попал сюда, я увидел вопрос и подумал: «Ну, просто трубка через awk». Но потом я увидел, что принятый ответ: «Эй, скачай этот сотни плагинов LOC и установи его». Третий ответ был: «Привет, скачайте тысячи плагинов LOC и установите их». Это перебор и раздувание. Даже если вам нужно суммировать столбцы более одного раза в жизни, это излишне. Мой ответ предназначен для того, чтобы показать, как вы можете сделать это с помощью одной команды no-plugins, no-nonsense, если вам нужно сделать это только один раз, и как вы можете сделать простую команду с параметрами из нее, если вам нужно это сделать. довольно часто.
JoL
@Hotschke Чтобы ответить на ваш вопрос, я использовал для установки каждый плагин под солнцем, который выглядел круто, но потом мой vim был невероятно медленным (читай «немного запаздывает», что недопустимо для редактора). Изучив больше vim docs, я понял, что мне не нужны плагины. Многие из стандартных функций были достаточно хороши, и для тех, у кого vim этого не было, шелл был подходящим вариантом. Основательно (игнорируя сделанные исключения), согласно философии Unix, vim - это редактор, который хорошо взаимодействует с другими инструментами ОС. Я считаю, что это лучший способ использовать его. Никаких плагинов с тех пор.
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

Vmap ++из плагина vmathДамиана Конвея

  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. Перейти к третьему 2f|столбцу и выбрать столбец в режиме визуального блока<C-V>G$
  4. Нажмите ++(или выбранное вами отображение)
  5. Результаты отображаются и сохраняются в регистрах (сумма в s)
  6. Введите сумму из регистра s, например, с помощью"sp

Презентацию этого плагина смотрите в видео на YouTube Дамиана Конвея «Более мгновенно лучше Vim» - OSCON 2013 (начиная с 29-й минуты).

Hotschke
источник
1

Внешний инструмент Clicsvstat от CSVKIT

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

Краткое объяснение вариантов

  • -d DELIMITERРазделительный символ входного CSV-файла. Here |.
  • -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.

Hotschke
источник