[英]How do I find and insert the average of multiple lines in Emacs / Elisp?
我有一個類似於以下文件:
AT 4
AT 5.6
AT 7.2
EG 6
EG 6
S 2
OP 3
OP 1.2
OP 40
我想計算每個標題的平均值(我已經將這些平均值進行了計算),並輸出如下內容:
AT 5.42
EG 6
S 2
OP 32.1
該文件是按順序排列的,因此所有標題都在彼此之間,但是標題的數量不同。 例如。 AT
有3個,而S
只有1個。
我如何將這些行中的每一行相加,除以行數,然后替換emacs / elisp中的所有行?
我決定嘗試解決這個問題,同時仍然要學習減少自己。 也許有更有效的方法來解決這個問題。
定義函數后,您需要設置分數附近的區域。 (如果是整個文件,則為M-<,C-SPC,M->),我認為這是最干凈的,因為您的分數可能位於其他文本的中間。 我的函數將計算平均值,然后將答案插入該區域的末尾。
(defun my/averages (beg end)
(interactive "r")
(let ((avgs (make-hash-table :test 'equal))
(answer "")
(curval nil)
(key nil)
(val nil))
; Process each line in region
(save-excursion
(goto-char beg)
(while (< (point) end)
; split line
(let ((split-line
(split-string
(buffer-substring-no-properties
(line-beginning-position) (line-end-position)))))
(setq
key (car split-line)
val (string-to-number (cadr split-line))
curval (gethash key avgs '(0 . 0)))
(puthash key (cons (+ (car curval) 1) (+ (cdr curval) val )) avgs))
; Advance to next line
(forward-line))
; Accumulate answer string
(maphash
(lambda (k v)
(setq answer
(concat answer "\n" k " "
(number-to-string (/ (cdr v) (car v))))))
avgs)
(end-of-line)
(insert answer))))
作為警告,我對不嚴格符合您格式的行進行了零錯誤檢查。
您需要庫dash
, s
, f
及其函數-map
, -sum
, -group-by
, s-split
和f-read-text
。
;; average
(defun avg (values)
(/ (-sum values) (length values)))
(-map (lambda (item)
(list (car item)
(avg (-map (lambda (x)
(string-to-number (cadr x)))
(cdr item)))))
(-group-by (lambda (item)
(car item))
(-map (lambda (line)
(s-split " " line t))
(s-split "[\n\r]"
(f-read-text "file.txt")
t))))
假設您的文件名為"file.txt"
,則上面的代碼返回(("AT" 5.6000000000000005) ("EG" 6) ("S" 2) ("OP" 14.733333333333334))
。
之后,您可以將其轉換為文本:
(s-join "\n"
(-map (lambda (item)
(s-join " "
(list (car item)
(number-to-string (cadr item)))))
您可以使用f-write-text
將這個字符串寫入文件。 別忘了,您可以像這樣格式化丑陋的浮點數:
(format "%.2f" 3.33333333) ; => "3.33"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.