请批评我的Lisp

Pau*_*han 13 lisp common-lisp

我创造了一个很好的小例程:

(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))))
Run Code Online (Sandbox Code Playgroud)

并使用它:

CL-USER> (unzip '(1 2 3 4 5 6))
((2 4 6) (1 3 5))
Run Code Online (Sandbox Code Playgroud)

但是,我敏锐地意识到我能用任何语言编写 botch C++,并希望对我unzip的Common Lisp风格进行一些分析.

Ram*_*ren 13

首先注意'()并且()是等价的,因为空列表是自我评估并且等于NIL,并且在任何情况下你都不需要LET中的那些,因为NIL`(let(variable)...)语法暗示,这就是为什么在给出起始值时,您需要在每个绑定周围使用括号.

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))))
Run Code Online (Sandbox Code Playgroud)

我个人更喜欢迭代迭代,使用它可以写成:

(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)))))
Run Code Online (Sandbox Code Playgroud)

甚至:

(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)))))
Run Code Online (Sandbox Code Playgroud)

编辑:附加说明:名称unzip通常表示略有不同的功能.参数名称应该是真的list,因为它seq会暗示该函数也需要向量.虽然可以使功能在通用序列上运行,但通常不推荐使用,因为列表和向量具有不同的性能特征.特别是,随机访问NTH是列表的线性时间,这意味着您几乎不应该使用它.即使时间成本微不足道,它通常也表明您应该使用不同的数据结构.


hua*_*uan 8

该函数(nth n list)需要遍历列表以访问第n个元素,即O(n)操作,并在实现中调用O(n)次,使整个过程为O(n ^ 2).您可以在O(n)中完成相同的操作:

(defun unzip (list)
  (loop for (x y) on list by #'cddr
        collect x into a
        collect y into b
        finally (return (list a b))))


Gab*_*abe 1

  • for-each您应该使用orcar和迭代列表直到列表为空,而不是cdr循环遍历列表的元素。
  • 我不会这么称呼它,unzip因为它不是 的反义词zip

编辑:更具体地说,我希望zip获取一对列表并返回一对列表,因此unzip应该获取一对列表并返回一对列表。我希望它看起来像我发现的这个例子:

(defun unzip (list)
  (let ((a '())
        (b '()))
    (for-each (lambda (i) (push (first i) a) (push (second i) b)) list)
    (values (nreverse a) (nreverse b))))
Run Code Online (Sandbox Code Playgroud)