我创建了一个不错的小程序:
(defun unzip (seq)
"Takes an even-length list and breaks it apart by evens/odd index"
(let ((oddresult '())
(evenresult '()))
(loop for n from 0 to (- (length seq) 1) do
(if (oddp n)
(push (nth n seq) oddresult)
(push (nth n seq) evenresult)))
(list (reverse oddresult) (reverse evenresult))))
并使用它:
CL-USER> (unzip '(1 2 3 4 5 6))
((2 4 6) (1 3 5))
但是,我敏锐地意识到我有能力用任何语言编写拙劣的 C++,并且希望对我的unzip
进行一些分析以获得良好的 Common Lisp 风格。
首先注意 '()
和 ()
是等价的,因为空列表是自评估的并且等于 NIL
,并且在任何如果您不需要 LET 中的那些因为 NIL
是由 `(let (variable) ...) 语法隐含的,这就是为什么在给出起始值时需要在每个绑定(bind)周围加上括号的原因。
并不是说在这种情况下必须使用 LET
。使用LOOP功能更广泛,这个函数可以写成:
(defun unzip (seq)
"Takes an even-length list and breaks it apart by evens/odd index"
(loop for n from 0
for element in seq
if (oddp n)
collect element into oddresult
else
collect element into evenresult
finally (return (list oddresult evenresult))))
个人比较喜欢iterate对于大多数迭代,使用它可以写成:
(defun unzip (seq)
"Takes an even-length list and breaks it apart by evens/odd index"
(iter (for element in seq)
(for n from 0)
(if (oddp n)
(collect element into oddresult)
(collect element into evenresult))
(finally (return (list oddresult evenresult)))))
甚至:
(defun unzip (seq)
"Takes an even-length list and breaks it apart by evens/odd index"
(iter (generate element in seq)
(collect (next element) into evenresult)
(collect (next element) into oddresult)
(finally (return (list oddresult evenresult)))))
编辑:附加说明:名称 unzip
通常表示一个略有不同的函数。参数名称实际上应该是 list
,因为 seq
表明该函数也采用向量。虽然可以让函数对广义序列进行操作,但通常不推荐这样做,因为列表和向量具有不同的性能特征。特别是,通过 NTH
的随机访问是列表的线性时间,这意味着您几乎不应该使用它。即使时间成本微不足道,它通常也表明您应该使用不同的数据结构。