使用键值对动态填充列表

时间:2014-04-02 22:35:27

标签: recursion scheme racket r5rs

我需要用对填充列表,例如:((x 10)(z 5))。

我目前的方法:

;;send the current list, and an id value pair
(define (setID idList ID VAL)

  (cond 
        ;;if the list is null, add the pair
        ((null? idList) (cons '(ID VAL) '()))    

        ;; if the ID already exists, overwrite it
        ((equal? ID (car(car idList)))  (cons '((cdr idList)) VAL))

        ;; continue the search
        (else  (setID (cdr idList) ID VAL))
  )
)

我意识到我还需要使用cons来保持列表的正确性,但第一个问题是当我执行(setID z 5)之类的操作时,返回的列表正好是:((id val)) 。显然,它需要((z 10))。反正有没有做过这样的事情?

3 个答案:

答案 0 :(得分:2)

您的代码存在三个主要问题:

  • 在此处:(cons '(ID VAL) '()))您正在构建一个值为(ID VAL)的新对 - 也就是说,第一个元素符号ID第二个符号VAL。这不是您想要的,您需要IDVAL。确保您了解quote的工作方式
  • 当您找到现有的ID时,您必须将新修改的对与列表的其余部分一起使用
  • 即使当前对不是我们正在寻找的那对,我们必须cons到输出。请记住:我们在遍历列表时正在构建答案

这就是我的意思:

;;send the current list, and an id value pair
(define (setID idList ID VAL)
  (cond 
    ;;if the list is null, add the pair
    ((null? idList) (cons (list ID VAL) '()))
    ;; if the ID already exists, overwrite it
    ((equal? ID (car (car idList))) (cons (list ID VAL) (cdr idList)))
    ;; continue the search
    (else (cons (car idList) (setID (cdr idList) ID VAL)))))

并且不要忘记执行此过程后返回的列表是 new ,如果要继续添加元素,则必须将其存储在某处或作为参数传递它 - 因为最初作为参数收到的列表保持不变。现在程序按预期工作:

(setID '() 'x 10)
=> '((x 10))

(setID '((x 10)) 'y 20)
=> '((x 10) (y 20))

(setID '((x 10) (y 20)) 'x 30)
=> '((x 30) (y 20))

答案 1 :(得分:1)

不要重新发明轮子,关联列表在方案中很常见

这里的易事是带头标的守卫。以便((x 10)(z 5))成为(*idList* (x 10)(z 5))

;;send the current list, and an id value pair
(define (setID! idList ID VAL)
;;if a function mutates data end it with a bang
  (let ((ID-VAL (assoc ID (cdr idList)))) 
        ;;assoc returns #f if no match, with the ID-VAL pair if there is a match
        (if ID-VAL
            (set-car! (cdr ID-VAL) VAL)  
                     ;; if the ID already exists, overwrite it     
            (set-cdr! idList (cons (list ID VAL) (cdr idList)))))
                     ;;if ID into in assoc-list, add the pair
    idList)      ;;return the idList

测试

(setID! '(*idList*) 'x 10)
;Value 3: (*idlist* (x 10))

(setID! '(*idlist* (x 10)) 'y 20)
;Value 4: (*idlist* (y 20) (x 10))

(setID! '(*idlist* (y 20) (x 10)) 'x 30)
;Value 9: (*idlist* (y 20) (x 30))

答案 2 :(得分:1)

这是来自@WorBlux的答案的Racket-y版本:

你的" setID"基本上已在Racket中以dict-set的名称定义。

(dict-set dict key v) → (and/c dict? immutable?)
   dict : (and/c dict? immutable?)
   key  : any/c
   v    : any/c
     

通过将dict映射到key来功能扩展v,覆盖key的任何现有映射,并返回扩展字典。如果exn:fail:contract不支持功能扩展或dict不是字典的允许密钥,则更新可能会失败,并显示key异常。

     

示例:

> (dict-set #hash() 'a "apple")
'#hash((a . "apple"))

> (dict-set #hash((a . "apple") (b . "beer")) 'b "banana")
'#hash((b . "banana") (a . "apple"))

> (dict-set '() 'a "apple")
'((a . "apple"))

> (dict-set '((a . "apple") (b . "beer")) 'b "banana")
'((a . "apple") (b . "banana"))

参见上面的最后两个例子。

当然,您可以使用dict-ref和其他功能按键查找值,或映射它们,依此类推。

请注意,dict-set与您描述的略有不同,因为assoc(由dict}使用(key . val)而不是(key val)。换句话说,它使用(cons key val)而不是(list key val)。使用(cons a b)而不是(cons a (cons b '()))存储两个项目效率更高。