1

我需要用对填写一个列表,例如:((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))。有没有办法做这样的事情?

4

3 回答 3

2

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

  • 在这里:(cons '(ID VAL) '()))您正在使用 value 构建一个新对(ID VAL)- 也就是说,第一个元素symbol ID,第二个元素symbol VAL。这不是你想要的,你想要的IDVAL确保您了解 a 的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)))))

并且不要忘记执行此过程后返回的列表是一个列表,如果您想继续向其中添加元素,则必须将其存储在某处或将其作为参数传递 - 因为最初作为参数接收的列表保持未修改. 现在程序按预期工作:

(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))
于 2014-04-02T22:48:19.490 回答
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))
于 2014-04-02T23:15:34.193 回答
1

这是@WorBlux 的答案的球拍版本:

您的 " 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通过映射keyv、覆盖 的任何现有映射key并返回扩展字典来进行功能扩展。如果不支持功能扩展或者不是字典的允许键,则更新可能会失败并出现exn:fail:contract异常。dictkey

例子:

> (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)not (key val)。换句话说,它使用(cons key val)not (list key val)(cons a b)使用than存储两个项目更有效(cons a (cons b '()))

于 2014-04-03T12:27:00.797 回答