lisp函数(在常见的lisp中计算数字)

时间:2015-08-20 09:57:31

标签: functional-programming common-lisp

我正在研究与C和lisp中处理偶数相关的程序相关的程序,完成了我的c程序,但仍然遇到了lisp的问题

isprime函数已定义,我需要帮助:

  1. 定义函数primesinlist,它返回lis中唯一的素数
  2. 这里到目前为止, 有什么帮助吗?

    (defun comprimento (lista)
      (if (null lista)
          0
        (1+ (comprimento (rest lista)))))

     (defun primesinlist (number-list)
          (let ((result ()))
            (dolist (number number-list)
              (when (isprime number)
                ( number result)))
            (nreverse result))) 

2 个答案:

答案 0 :(得分:2)

在处理之前,您需要flatten参数:

(defun primesinlist (number-list)
  (let ((result ()))
    (dolist (number (flatten number-list))
      (when (isprime number)
        (push number result)))
    (delete-duplicates (nreverse result))))

或者,如果您想避免使用fresh列表,请在展开时将其展平:

(defun primesinlist (number-list)
  (let ((result ()))
    (labels ((f (l)
               (dolist (x l)
                 (etypecase x
                   (integer (when (isprime x)
                              (push x result)))
                   (list (f x))))))
      (f number-list))
    (delete-duplicates (nreverse result))))

要计算不同的素数,请取primesinlist返回的列表的length

或者,您可以使用count-if

(count-if #'isprime (delete-duplicates (flatten number-list)))

答案 1 :(得分:0)

听起来你已经实现了素性测试,但为了完整起见,我们添加一个非常简单的算法,试图将数字除以小于它的平方根的数字:

(defun primep (x)
  "Very simple implementation of a primality test.  Checks 
for each n above 1 and below (sqrt x) whether n divides x.
Example:
  (mapcar 'primep '(2 3 4 5 6 7 8 9 10 11 12 13))
  ;=> (T T NIL T NIL T NIL NIL NIL T NIL T)
"
  (do ((sqrt-x (sqrt x))
       (i 2 (1+ i)))
      ((> i sqrt-x) t)
    (when (zerop (mod x i))
      (return nil))))

现在,您需要一种方法将可能嵌套的列表列表展平为单个列表。在解决这个问题时,我通常会发现使用cons-cells构建的 trees 更容易思考。这是一个有效的展平函数,它返回一个全新的列表。也就是说,它不与原始树共享任何结构。这可能很有用,特别是如果我们想稍后修改结果结构,而不修改原始输入。

(defun flatten-tree (x &optional (tail '()))
  "Efficiently flatten a tree of cons cells into 
a list of all the non-NIL leafs of the tree.  A completely
fresh list is returned.

Examples:
  (flatten-tree nil)                ;=> ()
  (flatten-tree 1)                  ;=> (1)
  (flatten-tree '(1 (2 (3)) (4) 5)) ;=> (1 2 3 4 5)
  (flatten-tree '(1 () () 5))       ;=> (1 5)
"
  (cond
    ((null x) tail)
    ((atom x) (list* x tail))
    ((consp x) (flatten-tree (car x)
                             (flatten-tree (cdr x) tail)))))

现在只需要清理列表,删除不是素数的数字,并从列表中删除重复项。 Common Lisp包含执行这些操作的功能,即 remove-if-not remove-duplicates 。这些是“安全”版本,不修改其输入参数。由于我们知道扁平化列表是新生成的,因此我们可以使用它们(可能)具有破坏性的对应物, delete-if-not delete-duplicates

但是,当你删除重复的元素时,有一个警告。如果您有(1 3 5 3)之类的列表,则可以返回两种可能的结果(假设您按顺序保留所有其他元素):(1 3 5)< / strong>和(1 5 3)。也就是说,您可以删除较晚的副本或较早的副本。一般来说,你有“应该留下哪一个?”的问题。默认情况下,Common Lisp删除之前的副本并保留最后一次出现。可以通过:from-end 关键字参数自定义该行为。在您自己的API中复制该行为可能会很好。

所以,这是一个将所有这些考虑因素放在一起的函数。

(defun primes-in-tree (tree &key from-end)
  "Flatten the tree, remove elements which are not prime numbers,
using FROM-END to determine whether earlier or later occurrences
are kept in the list.

Examples:
  (primes-in-list '(2 (7 4) ((3 3) 5) 6 7))
  ;;=> (2 3 5 7)

  (primes-in-list '(2 (7 4) ((3 3) 5) 6 7) :from-end t)
  ;;=> (2 7 3 5)"

  ;; Because FLATTEN-TREE returns a fresh list, it's OK
  ;; to use the destructive functions DELETE-IF-NOT and
  ;; DELETE-DUPLICATES.
  (delete-duplicates
   (delete-if-not 'primep (flatten-tree list))
   :from-end from-end))