首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >设计模式,用于并行使用两个列表,并返回其中一个列表的其余部分

设计模式,用于并行使用两个列表,并返回其中一个列表的其余部分
EN

Stack Overflow用户
提问于 2014-02-19 19:58:29
回答 2查看 97关注 0票数 2

摘要:抽象的问题是:

  • 值的列表
  • 一个修饰符列表,用于对值进行操作以返回新值的内容(对于示例代码,我只是将该值乘以修饰符值)
  • 修饰符列表不被限制为与值列表相同的大小。
  • 将修饰符应用于这些值,并获取所有未使用的修饰符。

下面是一个使用两个独立函数的版本:一个实际应用修饰符,另一个用于获取其余修饰符

代码语言:javascript
复制
;; 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)...
  • 当我在列表中回溯时,我会跟踪净累积的时间,以确定哪个修饰符对给定的注释有效。

因此,在真正的问题中,修饰符到值的映射并不容易,因此我希望遇到这样的情况:我将把一个修饰符列表应用到一个比音符列表更短的音符列表中;然后,我想将剩下的修饰符应用到下一个音符列表中(我计划将整个音乐分解成块)。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-02-19 21:27:49

假设这些是预期的结果:

代码语言:javascript
复制
> (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个列表:

代码语言:javascript
复制
(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,但我只能在等待示例时进行推测。在任何情况下,您都可以很容易地根据您的特定需求调整这段代码。

票数 2
EN

Stack Overflow用户

发布于 2014-02-19 22:15:22

听起来您可能需要一个可变的数据结构,比如队列。

代码语言:javascript
复制
(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))

然后是一个函数来组合它们

代码语言:javascript
复制
(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)和mod-queue (不管您现在将它传递给#queue (4 (dvol:-2).),而原来的便笺队列现在是一个空队列。

SICP中描述的队列

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21891060

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档