我在 dash
的函数里找了,但是没有找到需要的
(2 6 9) ;; 序号列表
(a b c d e f g h i j k l m n) ;; 原始列表
((a b c) (d e f g) (h i j) (k l m n)) ;; 拆分后的列表
我在 dash
的函数里找了,但是没有找到需要的
(2 6 9) ;; 序号列表
(a b c d e f g h i j k l m n) ;; 原始列表
((a b c) (d e f g) (h i j) (k l m n)) ;; 拆分后的列表
好像是没有现成的,不太了解 dash
,组合行么?
可能比较渣,仅供参考:
(defun my-split (index-list alist)
(-non-nil
(--map (-slice alist (car it) (cadr it))
(-partition-all-in-steps 2 1 (cons 0 (-map #'1+ (sort index-list #'<)))))))
(my-split '(2 6 9) '(a b c d e f g h i j k l m n))
;; => ((a b c) (d e f g) (h i j) (k l m n))
(defun your-split-by-indexes (list indexes)
(let ((idx 0)
(tmp ())
(result ()))
(dolist (elt list)
(push elt tmp)
(when (and indexes (= idx (car indexes)))
(pop indexes)
(push (reverse tmp) result)
(setq tmp nil))
(cl-incf idx))
(push (nreverse tmp) result)
(nreverse result)))
(your-split-by-indexes '(a b c d e f g h i j k l m n)
'(2 6 9))
;; => ((a b c) (d e f g) (h i j) (k l m n))
(your-split-by-indexes (number-sequence 0 9)
'(3 7))
;; => ((0 1 2 3) (4 5 6 7) (8 9))
学习了,已收藏
(defun split-by-indexes (LIST INDEXES)
(lexical-let* ((start 0))
(append
(mapcar (lambda (index)
(let* ((end (1+ index))
(s (-slice LIST start end)))
(setq start end)
s))
INDEXES)
(list (-slice LIST start)))))
(split-by-indexes '(a b c d e f g h i j k l m n) '(2 6 9))
;; => ((a b c) (d e f g) (h i j) (k l m n))
(split-by-indexes '(a b c d e f g h i) '(2 6 9))
;; => ((a b c) (d e f g) (h i) nil)
递归版:
(defun split-by-indexes-recursive (LIST INDEXES start)
(if INDEXES
(let ((end (1+ (car INDEXES))))
(append (list (-slice LIST start end))
(split-by-indexes-recursive LIST (cdr INDEXES) end)))
(list (-slice LIST start))))
(split-by-indexes-recursive '(a b c d e f g h i j k l m n) '(2 6 9) 0)
;; => ((a b c) (d e f g) (h i j) (k l m n))
(split-by-indexes-recursive '(a b c d e f g h i) '(2 6 9) 0)
;; => ((a b c) (d e f g) (h i) nil)
生成器版:
(setq lexical-binding t)
(require 'generator)
(iter-defun indexes-generator (INDEXES)
(let ((start 0)
(end (1+ (car INDEXES)))
(REMAINS (cdr INDEXES)))
(while end
(iter-yield (cons start end))
(cl-psetq start end
end (if (car REMAINS) (1+ (car REMAINS)))
REMAINS (cdr REMAINS)))
(iter-yield (cons start nil))))
(let* ((INDEXES '(2 6 9))
(LIST '(a b c d e f g h i j k l m n)))
(cl-loop for index-pair iter-by (indexes-generator INDEXES)
collect (-slice LIST (car index-pair) (cdr index-pair))))
;; => ((a b c) (d e f g) (h i j) (k l m n))
谢谢!已收藏
今天遇到一个类似的问题,就是按照 list 2 的样子改造 list 1 (也就是把 list 1 缺少的元素插入进去),这段代码分享如下:
(let ((list1 '(1 2 3 4 5 6 7 8))
(list2 '(a 1 2 3 b c 4 5 d e f 6 g 7 8 h))
(idx 0)
)
(dolist (item list2 list1)
(when (not (memq item list1))
(setq list1 (-insert-at idx item list1))
)
(cl-incf idx)
)
)
;; ===> (a 1 2 3 b c 4 5 d e f 6 g 7 8 h)
轻轻丢一个 -unfold
版本的,要比之前的 -slice
版更灵活:
(defun my-split (index-list alist)
(--unfold (pcase (and (car it) it)
(`(,al ,idx nil ) (list al))
(`(,al ,idx ,idxes)
(append (-split-at (- (car idxes) idx) al)
(list (car idxes) (cdr idxes)))))
(list alist -1 (-> index-list (sort #'<) (-uniq)))))
(my-split '(2 6 9) '(a b c d e f g h i j k l m n))
;; => ((a b c) (d e f g) (h i j) (k l m n))
似乎把 ,idxes
拆成 (,a . ,l)
更直观?不知效率上哪个更好。
大家对 dash.el
都挺熟,我几乎只了解 --map
。
(--map (+ 2 it) '(1 2 3))
;; => (3 4 5)
我是一点也不熟悉这个包
我是看了二楼的回复才知道有 --slice
方法。其它也不是很了解,印象比较深的是 -when-let
方法,emacs 内置包 subr-x 里也有个 when-let
方法,但是这两个行为不一致,被坑过一回所以长记性了:
;; dash
(-when-let (val 42)
(message "value: %d" val))
;; subr-x
(when-let ((val 42))
(message "value: %d" val))
回到楼主这个题目,最关键是产生拆分的起止点 (start . end)
。使用 dash 这样更高阶的函数库,可以写出更紧凑的代码,但是性能上难免要牺牲一点。
when-let
我赞成用 emacs 自带的,和 let 的用法比较一致
从一致性来讲,我也赞成。但是自带的 when-let
比较尴尬,一度说要废弃但是目前 26.1 又回归了(De-obsolete if-let
and when-let
)。这一局 dash 胜,或者说是 cl 的胜利(Macro When-Let )。
链接里多了一个中文句号
有一致的地方:when-let
也支持 (val 42)
:
(when-let (val 42)
(message "value: %d" val))
;; => "value: 42"
尽管 when-let*
只能用 ((val 42))
。
这个问题影响应该不大,因为原本计划废弃的也是 26.1。
刚才测试了一下,这两种写法对性能的影响几乎无区别,但现在比较疑惑 pcase
这类在什么时候用比较合适。
一些不太靠谱的总结(勿当真):
pcase
做 pattern,很吃性能,大概是纯 let
加 when
,if
的 70% 左右(仅测了这例)。when-let
,if-let
(同 -when-let
,-if-let
) 性能大概是 let
的 90%–95%。-slice
版本在数据列表很长时很渣(几到几十倍差距),而且序号列表越长越明显。dolist
版在序号列表越长时越稳定,还可以再优化,瓶颈是序号列表很短时停不下来:indexes
为 nil 时应及时跳出。-unfold
版很快,特别是序号列表很短时。不用 pcase
改用纯 let
,去掉了 ->
当中的语句,极端情况下不如 dolist
版,但大多数情况是差不多的,偶而还更快?有点出乎意料。