Как добавить элементы для структуры в Scheme / Lisp - PullRequest
2 голосов
/ 12 июля 2009

У меня есть вход, который имеет эту форму:

(((lady-in-water . 1.25)
  (snake . 1.75)
  (run . 2.25)
  (just-my-luck . 1.5))
 ((lady-in-water . 0.8235294117647058)
  (snake . 0.5882352941176471)
  (just-my-luck . 0.8235294117647058))
 ((lady-in-water . 0.8888888888888888)
  (snake . 1.5555555555555554)
  (just-my-luck . 1.3333333333333333)))

(контекст: слово обозначает фильм, а число обозначает взвешенный рейтинг, представленный пользователем)

Мне нужно добавить все количество и вернуть список, который выглядит примерно так

((lady-in-water 2.5)
 (snake 2.5)
 (run   2.25)
 (just-myluck 2.6))

Как пройти через список и все количества? Я действительно в тупик. Пожалуйста, помогите мне.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 12 июля 2009

Мой подход похож на описанный выше huaiyuan, но я предпочитаю использовать dolist для цикла:

(defun parse-ratings (all-ratings)
  (let ((hash (make-hash-table)))
    (dolist (rating-list all-ratings)
      (dolist (rating rating-list)
        (incf (gethash (car rating) hash 0)
              (cdr rating))))
    (maphash (lambda (key value) 
               (format t "total for ~a: ~a~%" key value))
             hash)))

, что приводит к следующему выводу:

CL-USER> (parse-ratings '(((lady-in-water . 1.25) (snake . 1.75) 
                          (run . 2.25) (just-my-luck . 1.5))
                         ((lady-in-water . 0.8235294117647058) 
                          (snake . 0.5882352941176471) 
                          (just-my-luck . 0.8235294117647058))
                         ((lady-in-water . 0.8888888888888888)
                          (snake . 1.5555555555555554) 
                          (just-my-luck . 1.3333333333333333))))
total for LADY-IN-WATER: 2.9624183
total for SNAKE: 3.893791
total for RUN: 2.25
total for JUST-MY-LUCK: 3.6568627
NIL
CL-USER> 
1 голос
/ 12 июля 2009

Во избежание неправильного представления о превосходстве CL в любом случае, вот решение PLT Scheme с использованием подхода хеш-таблицы. Я добавил sort результатов для дополнительного кредита.

(define (data->movies data)
  (define t (make-hasheq))
  (for* ([x (in-list data)] [x (in-list x)])
    (hash-set! t (car x) (+ (cdr x) (hash-ref t (car x) 0))))
  (sort (hash-map t cons) > #:key cdr))
1 голос
/ 12 июля 2009

В Common Lisp:

(defun marginalize (data)
  (let ((table (make-hash-table)))
    (loop for row in data do
      (loop for (k . v) in row do
        (incf (gethash k table 0.0) v)))
    (loop for k being the hash-key of table using (hash-value v)
          collect (cons k v))))
1 голос
/ 12 июля 2009

Вам нужно разбить проблему на две части: во-первых, преобразовать список в нечто вроде этого:

'(((lady-in-water . 1.25) (lady-in-water . 0.82) (lady-in-water . 0.88))
  ((snake . 1.75) ...)
  ...)

Я сделаю это, используя transpose:

(define (transpose ls)
  (if (null? (car ls))
      '()
      (cons (map car ls) (transpose (map cdr ls)))))

Тогда легко преобразовать список транспонированных фильмов в один список пар:

 (define (sum-movie movie)
   (cons (caar movie) (apply + (map cdr movie))))
 (define (sum-movies movies)
   (map sum-movie (transpose movies)))

Обратите внимание, что transpose небезопасно: произойдет сбой, если вы пропустите фильм в одном подсписке. Кроме того, использование transpose в первую очередь предполагает, что фильмы появляются в одном и том же порядке каждый раз.

...