Шаблон проектирования для одновременного использования двух списков и возврата остатка одного из списков

Абстракт: Абстрактная проблема:

  • список значений
  • список модификаторов, вещи, которые воздействуют на значения, чтобы возвращать новые значения (для примера кода я просто умножаю значение на значение модификатора)
  • список модификаторов не должен быть того же размера, что и список значений.
  • применить модификаторы к значениям и вернуть любые неиспользованные модификаторы

Вот версия, в которой используются две отдельные функции: одна для фактического применения модификаторов, другая для получения оставшихся модификаторов

;; Return the modified list
(define (apply-mods vals mods) 
    (if (or (null? vals) (null? mods)) vals
      (cons (* (car vals) (car mods)) (apply-mod (cdr vals) (cdr mods)))
    )
)
;; trim the modifiers 
(define (trim-mods vals mods)
    (if (or (null? vals) (null? mods)) mods
    (trim-mods (cdr vals) (cdr mods))
)

Идея заключается в том, что после применения списка модификаторов, (apply-mods vals mods) Я могу использовать оставшиеся модификаторы (trim-mods vals mods) в последующих операциях.

В настоящее время лучшим подходом, который я придумала, является двухфункциональный подход, но кажется бесполезным повторять список дважды.

Есть ли чистый способ вернуть как измененные значения, так и неиспользованные модификаторы?

Бетон Конкретная проблема заключается в:

  • мои ценности - музыкальные ноты; у каждого есть объем и продолжительность. Что-то вроде:(vol: 1, dur: 1 beat)(vol: 1 dur: 2 beats)(vol: 1 dur: 1 beat)...
  • мои модификаторы "изменения громкости", у каждого есть изменение громкости и продолжительность(dvol: +1 dur: 4 beats)(dvol: -2 dur: 4 beats)...
  • просматривая списки, я отслеживаю общее накопленное время, чтобы определить, какой модификатор действует для данной заметки.

Таким образом, в реальной проблеме нет простого преобразования 1-1 модификаторов в значения, и поэтому я ожидаю столкнуться с ситуациями, когда я применю список модификаторов к списку заметок, который короче (с точки зрения длительности) чем список заметок; Затем я хочу применить оставшиеся модификаторы к следующему списку заметок (я планирую разбить всю музыку на куски).

2 ответа

Решение

Предполагая, что это ожидаемые результаты:

> (apply-mods '((1 . 10)) '((1 . 4) (2 . 4) (3 . 4)))
'((2 . 4) (3 . 4) (4 . 2))
'((3 . 2))

> (apply-mods '((1 . 1) (1 . 2) (1 . 1)) '((+1 . 4) (-2 . 4)))
'((2 . 1) (2 . 2) (2 . 1))
'((-2 . 4))

это простой цикл обработки 2 списков параллельно:

(define (apply-mods vals mods)
  (let loop ((vals vals) (mods mods) (res null))
    (cond
      ((null? vals) (values (reverse res) mods))
      ((null? mods) (error "not enough mods"))
      (else
       (let ((val (car vals)) (mod (car mods)))
         (let ((vol (car val)) (dur (cdr val)) (dvol (car mod)) (ddur (cdr mod)))
           (cond
             ; case 1. duration of note = duration of mod => consume note and mod
             ((= dur ddur)
              (loop (cdr vals) 
                    (cdr mods) 
                    (cons (cons (+ vol dvol) dur) res)))
             ; case 2. duration of note < duration of mod => consume note, push back shorter mod
             ((< dur ddur) 
              (loop (cdr vals) 
                    (cons (cons dvol (- ddur dur)) (cdr mods)) 
                    (cons (cons (+ vol dvol) dur) res)))
             ; case 3. duration of note > duration of mod => push back part of note, consume mod
             (else         
              (loop (cons (cons vol (- dur ddur)) (cdr vals)) 
                    (cdr mods) 
                    (cons (cons (+ vol dvol) ddur) res))))))))))

Кажется, что ваше требование еще проще, и вам, вероятно, нужно только охватить случай 1, но я могу только строить догадки, ожидая примера. В любом случае вы сможете легко адаптировать этот код к вашим конкретным потребностям.

Похоже, вам может понадобиться изменяемая структура данных, например, очередь.

(make-mod-queue '(dvol: +1 dur: 4 beats)(dvol: -2 dur: 4 beats)...))

#queue((4 (dvol: +1)) (4 (dvol: -2)) ...)

(make-note-queue '(vol: 1, dur: 1 beat)(vol: 1 dur: 2 beats)(vol: 1 dur: 1 beat))

#queue((1 (vol" 1)) (1 (vol: 1)) (2 (vol: 1))

Тогда функция для их объединения

(define (apply-mods note-queue mod-queue)
 (let ((new-queue make-empty-queue))
       (get-note-dur (lambda () 
                      (if (emtpy-queue? note-queue)
                          #f  
                          (car (front-queue note-queue)))))
       (get-mod-dur (lambda () 
                      (if (empty-queue? mod-queue)
                          #f
                          (car (front-queue mod-queue)))))
       (get-vol 
          (lambda () 
            (if (or (empty-queue? mod-queue) (empty-queue? mod-queue))
                 #f        
                 (+ (note-vol (front-queue note-queue)) 
                    (mod-vol  (front-queue mod-queue)))))))
   (let loop ((d1 (get-note-dur)) ;;should return #f is note-queue is empty
              (d2 (get-mod-dur))  ;;ditto for mod-queue
              (vol (get-volume))) 
    (cond ((not vol) 
           (cond ((and d2 (not (= d2 (get-mod-dur))))
                  (set-car! (front-queue mod-queue) d2) new-queue)
                  new-queue)
                 ((and d1 (not (= d1 (get-note-dur))))
                  (set-car! (front-queue note-queue) d1) new-queue)
                  new-queue)
                 (else new-queue)))
          ((= d1 d2)
           (insert-queue! new-queue (cons d1 (list 'vol: vol)))
           (delete-queue! note-queue)
           (delete-queue! mod-queue)
           (loop (get-note-dur) (get-mod-dur) (get-volume)
          ((< d1 d2)
           (insert-queue! new-queue (cons d1 (list 'vol: vol)))
           (delete-queue! note-queue)
           (loop (get-note-dur) (- d2 d1) (get-volume)))
          ((> d1 d2)
           (insert-queue! new-queue (cons d2 (list 'vol: vol)))
           (delete-queue! mod-queue)
           (loop (- d1 d2) (get-mod-dur) (get-volume)))))))

Возвращает #queue (1 (vol "2)) (1 (vol: 2)) (2 (vol: 2) и вашу мод-очередь (что бы вы ни передавали, как теперь будет преобразовано в #queue (4 (dvol): -2))...), а исходная очередь заметок теперь пустая

очереди, как описано в SICP

http://mitpress.mit.edu/sicp/full-text/sicp/book/node62.html

Другие вопросы по тегам