คำนวณผลรวมของตัวเลขอย่างรวดเร็ว


15

ฉันกำลังเขียนตาราง markdown ซึ่งมีลักษณะดังนี้:

| 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 คีย์ผสม หากใครบางคนต้องการสคริปต์ของฉันจริงๆเขา / เธอจะตรวจสอบรายละเอียดต่อไป
Kent

12

หากคุณไม่ต้องการใช้ปลั๊กอินหรือวางเพื่อสคริปต์ทุบตีคุณสามารถทำสิ่งต่อไปนี้:

  • c-V {motions} "ay คัดลอกคอลัมน์ลงใน "a
  • :let @a = substitute(@a, 'c-V c-J', '+', 'g') แทนที่คอลัมน์ขึ้นบรรทัดใหม่ด้วย +
  • ic-R=c-Raรันการแทนที่"aผ่านนิพจน์รีจิสเตอร์

อีกทางหนึ่ง: ทำให้รายการประวัตินิพจน์สามารถใช้งานได้อีกครั้งสำหรับจำนวนคอลัมน์เพิ่มเติม

  • ctrl-V {motions} y ใส่คอลัมน์ใน yank register ""
  • 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

@Hovercouch คุณช่วยอธิบายขั้นตอนที่สามได้ไหม? วิธีการอย่างใดอย่างหนึ่งจะไปเกี่ยวกับการเรียกใช้การแทนที่ผ่านการลงทะเบียนการแสดงออก?
pdoherty926

วิธีทำแผนที่: `nnoremap <cs>: s / $ / \ = eval (ทดแทน (@ 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

หากคุณต้องการลองใช้ฟังก์ชั่นนี้ให้ทำดังต่อไปนี้: คัดลอกฟังก์ชั่นนี้ในเบราว์เซอร์ของคุณและเรียกใช้คำสั่ง:@+ นี้เป็นกลุ่มซึ่งจะช่วยให้คุณสามารถใช้งานได้:call SumVis()ตามปกติ

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

มันต้องการให้คุณทำการเลือกบล็อกภาพด้วยctrl+ v, ยกเลิกการเลือกและสุดท้ายเรียกใช้ฟังก์ชัน หรือคุณสามารถใช้แผนที่ที่แนะนำซึ่งจะลบการเลือกก่อนที่จะคำนวณ



5

การสร้างปลั๊กอินหรือการเข้ารหัสใน vimscript นั้นค่อนข้างหนัก ฉันเชื่อในเสียงเรียกเข้าที่ไม่มีปลั๊กอินและการจัดวางที่ดีกับเครื่องมือภายนอก

นี่คือคำสั่งแบบ 1 ครั้งโดยอ้างอิงจากผู้ใช้ 2571881 ซึ่งใช้ได้แม้ว่าบัฟเฟอร์จะไม่ถูกบันทึก

:%!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-surround, vim-fugitive, vim-easy-align / vim-lion, vim-unimpaired, vim-commentary, ultisnips หรือฟุตเฉพาะเจาะจงเช่น vim-go, vim-rails, vimtex?
Hotschke

@ Hotschke เมื่อฉันมาถึงที่นี่ฉันเห็นคำถามและคิดว่า "ก็แค่ไปทาง awk" แต่จากนั้นฉันเห็นคำตอบที่ยอมรับคือ "เฮ้ดาวน์โหลดปลั๊กอิน LOC หลายร้อยตัวนี้แล้วติดตั้ง" คำตอบที่สามคือ "เฮ้ดาวน์โหลดปลั๊กอิน LOC นี้นับพันแล้วติดตั้ง" มันมากเกินไปและขยายตัว แม้ว่าคุณจะต้องรวมคอลัมน์มากกว่าหนึ่งครั้งในชีวิตของคุณมันก็เกินความจริง คำตอบของฉันมีไว้เพื่อแสดงว่าคุณสามารถทำสิ่งนี้ได้อย่างไรในคำสั่ง no-plugins คำสั่งที่ไร้สาระถ้าคุณต้องการทำสิ่งนี้เพียงครั้งเดียวและวิธีที่คุณสามารถสร้างคำสั่งอย่างง่ายโดยใช้พารามิเตอร์ถ้าคุณต้องการ บ่อยครั้ง.
JoL

@ Hotschke เพื่อตอบคำถามของคุณฉันเคยติดตั้งปลั๊กอินทุกอันภายใต้ดวงอาทิตย์ที่ดูเท่ห์จากระยะไกล แต่แล้วเสียงเรียกเข้าของฉันก็ช้าอย่างไม่น่าเชื่อ (อ่าน "ความล่าช้าเล็กน้อย" ซึ่งแก้ไขไม่ได้) เมื่อดูเพิ่มเติมในกลุ่มเอกสารฉันรู้ว่าฉันไม่ต้องการปลั๊กอินจริงๆ คุณสมบัติสต็อกจำนวนมากนั้นดีพอและสำหรับผู้ที่ไม่มีกลุ่มเปลือกก็เป็นวิธีที่จะไป พื้นฐาน (ละเว้นข้อยกเว้นที่ทำ), ตามปรัชญาของ Unix, vim เป็นตัวแก้ไขที่ทำงานร่วมกันได้ดีกับเครื่องมือระบบปฏิบัติการอื่น ๆ ฉันเชื่อว่าเป็นวิธีที่จะใช้ประโยชน์ได้ดีที่สุด ไม่มีปลั๊กอินตั้งแต่
JoL

2

หากคอลัมน์อยู่ในแนวที่ถูกต้องก็สามารถทำได้ด้วยการแสดงผลแบบง่าย

  1. ก่อนอื่นให้เลือกคอลัมน์ในโหมดภาพบล็อกบล็อคเนื่องจากคำตอบอื่น ๆ ได้แสดง -> CTRL-V+ เลื่อนเคอร์เซอร์
  2. ดึงส่วนที่เลือกด้วย y
  3. ประเภท: :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
....

หมายเหตุ: ที่นี่ฉันใช้ lambdas จาก Vim 7.4.1xxx


1

vmap ++จากปลั๊กอินvmathโดย Damian Conway

  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 Damian Conway, "More Vim Better Betterly" - OSCON 2013 (เริ่มที่ 29 นาที)


1

เครื่องมือ cli ภายนอกcsvstatจากcsvkit

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

คำอธิบายสั้น ๆ ของตัวเลือก

  • -d DELIMITERการย่ออักขระของไฟล์ CSV อินพุต |ที่นี่
  • -H ระบุว่าไฟล์ CSV อินพุตไม่มีแถวส่วนหัว
  • -c COLUMNSรายการที่คั่นด้วยเครื่องหมายจุลภาคของดัชนีคอลัมน์หรือชื่อที่จะตรวจสอบ เริ่มต้นที่คอลัมน์ทั้งหมด
  • --sum จำนวนเงินเอาท์พุทเท่านั้น

เครื่องมือนี้ยังให้ข้อมูลนาที, สูงสุด, ค่าเฉลี่ย, ค่ามัธยฐาน, stdev (ค่าเบี่ยงเบนมาตรฐาน), นับค่าที่ไม่ซ้ำ, รายการค่าที่พบบ่อย

แทรกลงในไฟล์ด้วย

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