首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何消除Lisp代码中的冗余?

如何消除Lisp代码中的冗余?
EN

Stack Overflow用户
提问于 2016-01-20 19:59:22
回答 1查看 260关注 0票数 6

我尝试在Common中实现快速排序,到目前为止,我已经得到了这样的结果:

代码语言:javascript
复制
(defun quick-sort (list)
  (if (cdr list)
    (let ((pivot (car list)))
      (append (quick-sort (remove-if-not (lambda (n) (< n pivot)) list))
              (remove-if-not (lambda (n) (= n pivot)) list)
              (quick-sort (remove-if-not (lambda (n) (> n pivot)) list))))
    list))

显然它起作用了,但我认为代码中有太多的重复。基本上,我们有三次:

代码语言:javascript
复制
(remove-if-not (lambda (n) (< n pivot)) list)

这三个调用的唯一不同之处是>=<

因此,我的问题是:如何才能消除这种冗余,使代码更加可读性和紧凑性?

当然,我可以提取函数的内容,例如:

代码语言:javascript
复制
(defun which (operator pivot list )
  (remove-if-not (lambda (n) (funcall operator n pivot)) list))

(defun quick-sort (list)
  (if (cdr list)
    (let ((pivot (car list)))
      (append (quick-sort (which #'< pivot list))
              (which #'= pivot list)
              (quick-sort (which #'> pivot list))))
    list))

但不知何故,我不太相信这是否是最好的方法。不得不一次又一次地交出pivotlist,这仍然让人感到笨拙。

我还想使用flet,它使函数的实际主体更易读,但只将复杂性转移到其他地方:

代码语言:javascript
复制
(defun quick-sort (list)
  (if (cdr list)
    (let ((pivot (car list)))
      (flet ((left () (remove-if-not (lambda (n) (< n pivot)) list))
             (middle () (remove-if-not (lambda (n) (= n pivot)) list))
             (right () (remove-if-not (lambda (n) (> n pivot)) list)))
        (append (quick-sort (left))
                (middle)
                (quick-sort (right)))))
    list))

还有其他方法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-20 20:17:22

如果将其编写为本地函数,则不必传递额外的参数,因为它们在作用域中。

代码语言:javascript
复制
(defun quick-sort (list)
  (if (rest list)
      (let ((pivot (first list)))
        (flet ((filter (operator)
                 (remove-if-not (lambda (n) (funcall operator n pivot)) list)))
          (append (quick-sort (filter #'<))
                  (filter #'=)
                  (quick-sort (filter #'>)))))
    list))

一个稍微紧凑的版本:

代码语言:javascript
复制
(defun quick-sort (list &aux (pivot (first list)))
  (flet ((filter (operator)
           (remove-if-not (lambda (n) (funcall operator n pivot)) list)))
    (and list
         (nconc (quick-sort (filter #'<))
                (filter #'=)
                (quick-sort (filter #'>))))))

由于Common支持多个值,所以还可以一次将列表划分为一个函数,并将列表作为值返回:

代码语言:javascript
复制
(defun partition (list pivot)
  (loop for e in list
        when (< e pivot) collect e into smaller else
        when (> e pivot) collect e into larger else
        when (= e pivot) collect e into same
        finally (return (values smaller same larger))))

(defun quick-sort (list)
  (if (rest list)
      (multiple-value-bind (smaller same larger)
          (partition list (first list))
        (append (quick-sort smaller) same (quick-sort larger)))
    list))

当列表是新分配的,那么NCONC是可能的。由于REMOVE-IF-NOT是无损的(与DELETE-IF-NOT相比),NCONC是好的.由于LOOP收集新的列表,所以NCONC再次正常。

这是一个实际的简单的就地快速排序向量。请注意,快速排序实际上是这样的意思。使用列表的版本实际上不是快速排序。

代码语言:javascript
复制
(defun partition (array left right &aux (i (1- left))
                                        (j right)
                                        (v (aref array right)))
  (loop do (loop do (incf i) until (>= (aref array i) v))
           (loop do (decf j) until (or (zerop j)
                                       (<= (aref array j) v)))
           (rotatef (aref array i) (aref array j))
        until (<= j i))
  (rotatef (aref array j) (aref array i) (aref array right))
  i)

(defun quicksort (array &optional (left 0) (right (1- (length array))))
  (if (> right left)
    (let ((i (partition array left right)))
      (quicksort array left (1- i))
      (quicksort array (1+ i) right))
    array))

此版本基于Sedgewick的代码。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34909372

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档