まず、Joswig 氏に同意します。Stackoverflow は宿題の答えを求める場所ではありません。ただし、追加の掘り下げと、ハッシュテーブルと字句閉鎖がどのように機能するかを理解できるようにしないと、直接使用できない可能性があるという方法であなたの質問に答えます。これは、あなたの進歩のための良い練習になります。
重複を削除せずにすべての値を 1 回だけカウントする方法はありますか? 方法があれば、再帰によって実行できますか?
はい、ハッシュテーブルを使用すると簡単です。2 つの例を次に示します。
;; no state stored
(defun make-bag (lst)
(let ((hs (make-hash-table)))
(labels ((%make-bag (lst)
(if lst
(multiple-value-bind (val exists)
(gethash (car lst) hs)
(if exists
(setf (gethash (car lst) hs) (1+ val))
(setf (gethash (car lst) hs) 1))
(%make-bag (cdr lst)))
hs)))
(%make-bag lst))))
ここで、このフォームを 2 回評価しようとすると、毎回同じ答えが得られます。
(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T
(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T
そして、これは 2 番目の例です。
;; state is stored....
(let ((hs (make-hash-table)))
(defun make-bag (lst)
(if lst
(multiple-value-bind (val exists)
(gethash (car lst) hs)
(if exists
(setf (gethash (car lst) hs) (1+ val))
(setf (gethash (car lst) hs) 1))
(make-bag (cdr lst)))
hs)))
ここで、このフォームを 2 回評価しようとすると、2 回目の回答は 2 倍になります。
(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 5
> T
(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 10
> T
なぜ答えが2倍になったのですか?
ハッシュテーブルの内容を連想リストに変換するには?
また、再帰関数は通常、リストを「食べる」ものであり、各ステップの結果を蓄積するアキュムレータを持っている場合があり、最後に返されることにも注意してください。ハッシュ テーブルと remove-duplicates/count-if を使用する機能がないと、基本的な関数を使用する必要があるため、ロジックが少し複雑になります。