1

I am working on program related to the different of dealing with even numbers in C and lisp , finished my c program but still having troubles with lisp

isprime function is defined and I need help in:

  1. define function primesinlist that returns unique prime numbers in a lis

here what i got so far , any help with that please?

(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))) 
sos
  • 15
  • 3

2 Answers2

2

You need to either flatten the argument before processing:

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

or, if you want to avoid consing up a fresh list, flatten it as you go:

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

To count distinct primes, take the length of the list returned by primesinlist.

Alternatively, you can use count-if:

(count-if #'isprime (delete-duplicates (flatten number-list)))
Community
  • 1
  • 1
sds
  • 58,617
  • 29
  • 161
  • 278
0

It sounds like you've already got a primality test implemented, but for sake of completeness, lets add a very simple one that just tries to divide a number by the numbers less than it up to its square root:

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

Now, you need a way to flatten a potentially nested list of lists into a single list. When approaching this problem, I usually find it a bit easier to think in terms of trees built of cons-cells. Here's an efficient flattening function that returns a completely new list. That is, it doesn't share any structure with the original tree. That can be useful, especially if we want to modify the resulting structure later, without modifying the original input.

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

Now it's just a matter of flatting a list, removing the number that are not prime, and removing duplicates from that list. Common Lisp includes functions for doing these things, namely remove-if-not and remove-duplicates. Those are the "safe" versions that don't modify their input arguments. Since we know that the flattened list is freshly generated, we can use their (potentially) destructive counterparts, delete-if-not and delete-duplicates.

There's a caveat when you're removing duplicate elements, though. If you have a list like (1 3 5 3), there are two possible results that could be returned (assuming you keep all the other elements in order): (1 3 5) and (1 5 3). That is, you can either remove the the later duplicate or the earlier duplicate. In general, you have the question of "which one should be left behind?" Common Lisp, by default, removes the earlier duplicate and leaves the last occurrence. That behavior can be customized by the :from-end keyword argument. It can be nice to duplicate that behavior in your own API.

So, here's a function that puts all those considerations together.

(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))
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353