【问题标题】:lisp functions ( count numbers in common lisp)lisp 函数(普通 lisp 中的计数)
【发布时间】:2015-11-13 21:53:21
【问题描述】:

我正在开发与在 C 和 lisp 中处理偶数不同的程序,完成了我的 c 程序但仍然遇到 lisp 的问题

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

  1. 定义函数primesinlist,在一个lis中返回唯一的素数

到目前为止我得到了什么, 请问有什么帮助吗?

(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))) 

【问题讨论】:

    标签: functional-programming common-lisp


    【解决方案1】:

    在处理之前你需要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)))
    

    【讨论】:

    • 您不能使用count-if,因为您需要唯一性。
    【解决方案2】:

    听起来您已经实现了素数测试,但为了完整起见,让我们添加一个非常简单的测试,它只是尝试将一个数字除以小于它的数字直到其平方根:

    (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-notremove-duplicates。这些是不修改其输入参数的“安全”版本。由于我们知道扁平化列表是新生成的,因此我们可以使用它们(可能)具有破坏性的对应物,delete-if-notdelete-duplicates

    不过,在删除重复元素时需要注意。如果您有一个类似 (1 3 5 3) 的列表,则可能会返回两种结果(假设您保持所有其他元素按顺序排列):(1 3 5) 和 (1 5 3)。也就是说,您可以删除较晚的副本或较早的副本。一般来说,你有一个问题是“应该留下哪一个?”默认情况下,Common Lisp 会删除 earlier 重复项并保留最后一次出现。该行为可以通过 :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))
    

    【讨论】:

      猜你喜欢
      • 2022-11-27
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 2011-01-21
      • 2020-06-01
      • 2012-03-25
      • 2020-08-16
      • 1970-01-01
      相关资源
      最近更新 更多