Я думаю, что вы хотите вычислить процентную долю списка, равную каждому элементу. Вы использовали слово «уникальный», но это немного сбивает с толку, поскольку в вашем списке нет уникальных элементов. Это основано на ваших примерах ввода и вывода, где список (1 2 1 1 2 3 3 4 4 4)
состоит из "30% единиц".
Вы можете грубо разбить это на рекурсивный алгоритм, состоящий из следующих шагов:
- Если список ввода пуст, вернуть пустой список.
- В противном случае получите первый элемент. Подсчитайте, сколько раз это встречается в списке.
- Рассчитайте процент и
cons
элемент с этим процентом.
- Удалить все вхождения первого элемента из
cdr
списка.
- Запишитесь в этом новом списке и
cons
составьте список из (element . percentage)
пар.
Для выполнения первой части давайте используем filter
:
> (filter (lambda (x) (eq? (car A) x)) A)
(1 1 1)
С вашим списком A это вернет список (1 1 1)
. Затем мы можем использовать длину, чтобы узнать, сколько раз это произошло:
> (length (filter (lambda (x) (eq? (car A) x)) A))
3
Чтобы рассчитать процент, разделите на количество элементов во всем списке или (length A)
и умножьте на 100:
> (* 100 (/ (length (filter (lambda (x) (eq? (car A) x)) A)) (length A)))
30
Это просто cons
с помощью элемента (car A)
, чтобы получить пару для окончательного списка.
Чтобы сделать второй шаг, мы можем использовать remove
, обратное filter
: он вернет список всех элементов исходного списка, которые не удовлетворяют функции предиката:
> (remove (lambda (x) (eq? (car A) x)) A)
(2 2 3 3 4 4 4)
Это список, в который мы хотим вернуться. Обратите внимание, что на каждом шаге вы должны иметь исходный список (или длину исходного списка) и этот новый список. Поэтому вам нужно как-то сделать это доступным для рекурсивной процедуры, либо с помощью дополнительного аргумента, либо с помощью определения внутреннего определения.
Может быть, есть более эффективные способы, я уверен, или просто другие способы, но это было решением, которое я нашел, когда читал вопрос. Надеюсь, это поможет!
(define (percentages all)
(let ((len (length all))) ; pre-calculate the length
;; this is an internal definition which is called at ***
(define (p rest)
(if (null? rest)
rest
;; equal-to is a list of all the elements equal to the first
;; ie something like (1 1 1)
(let ((equal-to (filter (lambda (x) (eq? (car rest) x))
rest))
;; not-equal-to is the rest of the list
;; ie something like (2 2 3 3 4 4 4)
(not-equal-to (remove (lambda (x) (eq? (car rest) x))
rest)))
(cons (cons (car rest) (* 100 (/ (length equal-to) len)))
;; recurse on the rest of the list
(p not-equal-to)))))
(p all))) ; ***