Apply v.s. Reduce


#1

1 + 2 + 3 + ... + 10000000 时间对比:

(setq numbers (number-sequence 1 (expt 10 7)))

(chart-bar-quickie
 'vertical
 "Apply v.s. Reduce"
 '("Apply" "Loop" "seq-reduce" "cl-reduce") "Method"
 (mapcar
  #'car
  (list (benchmark-run (apply #'+ numbers))
        (benchmark-run-compiled (cl-loop for i in numbers
                                         sum i))
        (benchmark-run (seq-reduce #'+ numbers 0))
        (benchmark-run (cl-reduce #'+ numbers))))
 "Seconds")
(benchmark-run (apply #'+ numbers))
;; => (0.155604 0 0.0)

(benchmark-run-compiled
    (cl-loop for i in numbers
             sum i))
;; => (0.316804 0 0.0)

(benchmark-run 1 (seq-reduce #'+ numbers 0))
;; => (1.328944 0 0.0)

(benchmark-run (cl-reduce #'+ numbers))
;; => (1.814373 1 0.4932320000000061)

启发自:


#2

学到了chart-bar-quickie


#3

于是我加上-reduce又测了一次

(let ((numbers (number-sequence 1 (expt 10 7))))
  (chart-bar-quickie
   'vertical
   "Apply v.s. Reduce"
   '("Apply" "Loop" "seq-reduce" "cl-reduce" "-reduce") "Method"
   (mapcar
    #'car
    (list (benchmark-run (apply #'+ numbers))
          (benchmark-run-compiled (cl-loop for i in numbers
                                           sum i))
          (benchmark-run (seq-reduce #'+ numbers 0))
          (benchmark-run (cl-reduce #'+ numbers))
          (benchmark-run (-reduce #'+ numbers))))
   "Seconds"))


#4

结果不意外。

apply 调用了一次,reduce 调用了 (1- (length numbers)) 次:

(apply '+ '(1 2 3))
;; => (+ 1 2 3)

(-reduce '+ '(1 2 3))
;; => (+ (+ 1 2) 3)

reduce 在这个测试中是比较吃亏的,+ 函数没有体现 reduce 的意义:

(-reduce (lambda (acc n)
           (+ acc n))
         '(1 2 3))

#5

chart 在 elisp 手册里都没有,究竟是怎么发现这个东西的……


#6

这里?

这个博客有一篇关于 rx 的文章在[实用技巧]Emacs Lisp生成正则表达式 有提到:


#7

:+1: 感谢分享,很赞的博客。


#8

这个博客的代码高亮有点厉害,还带rainbow-delimeters-mode