Похоже, у вас уже есть тест на простоту реализации, но для полноты картины, позволяет добавить очень простой, который просто пытается разделить число числа меньше, чем до его квадратного корня:
(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. Вот эффективная функция сглаживания, которая возвращает совершенно новый список. То есть он не имеет никакой структуры с исходным деревом. Это может быть полезно, особенно если мы хотим позже модифицировать результирующую структуру без изменения исходного ввода.
(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) и (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))
Вы не можете использовать 'count-if', потому что вам нужны уникальные возможности. – sds
@sos: см. Править. – sds