簡體   English   中英

如何在Emacs / Elisp中查找並插入多行的平均值?

[英]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))))

作為警告,我對不嚴格符合您格式的行進行了零錯誤檢查。

您需要庫dashsf及其函數-map-sum-group-bys-splitf-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM