在Racket中,如何返回一个列表,其中包含两个不同词典中出现的所有键

时间:2019-07-17 06:31:52

标签: list dictionary scheme racket

我基本上只是想找到存在于两个不同字典中的键,并将这些键输入到列表中。

到目前为止,这是我的代码

(define-struct asc (key val))
;; An Asc is a (make-asc Any Any)
;; a Dict (dictionary) is a (listof Asc)


(define (common-keys D1 D2)
  (cond
    [(or (empty? D1) (empty? D2)) '()]
    [(equal?  (asc-val (first D1)) (asc-val (first D2)))
 (cons (asc-key (first D1)))]
    [ else (cons (asc-key (first D1 (common-keys (rest D1) (rest D2)))))])) 

该代码显然不起作用。对于这个问题,我的思考过程是首先检查两个字典是否为空,然后查看两个字典中的第一个值是否相等,如果相等,则构造一个列表。现在,我需要添加一个部分,然后在该部分中遍历其余词典,以查看其他键是否相等。我不确定如何执行此操作,我仍然无法同时处理多个列表,因此一次处理多个词典对我来说有点棘手。

这是一个测试案例示例

(check-expect (common-keys
               (list (make-asc 1 "one") (make-asc 15 "fifteen"))
               (list (make-asc 15 "fifteen") (make-asc 8 "eight")))
              (list 15)) 

由于15是两个字典中函数应返回的唯一值(列表15)

2 个答案:

答案 0 :(得分:3)

您的方法存在的问题是,您假设元素在两个字典中都位于相同的位置,但并非总是如此。您必须对照另一本词典中的所有所有其他键检查一本词典中的每个键,如果您为此构建了一个辅助程序,则会更加简单。

但是等等!如果我们考虑高阶过程,则有一个更简单的解决方案。我们只需要在每个字典的键上进行 map 映射,然后相交即可。比说的容易:

(define (common-keys D1 D2)
  (set-intersect
   (map asc-key D1)
   (map asc-key D2)))

它按预期工作:

(common-keys
 (list (make-asc 1 "one") (make-asc 15 "fifteen"))
 (list (make-asc 15 "fifteen") (make-asc 8 "eight")))
=> '(15)

答案 1 :(得分:0)

更多示例(仅用于教育目的) 与路径递归列表相交。

只是向您展示如何使用原始方法来完成它。

您必须首先对列表进行排序。然后并行比较两个列表的前两个元素。如果它们相等,则将它们收集在累加器(acc)中。如果不消除,则消除较小的第一个元素,并将list-intersect应用于缩小和未缩小的列表...直到至少一个列表或两个列表为空。

因此,您需要指定两个测试功能:

  • test-equal用于密钥和
  • 的相等性测试
  • test-less用于测试一个键是否小于另一个。
(define-struct asc (key val))

(define (list-intersect lst1 lst2 (acc '()) #:test-equal (test-equal =) #:test-less (test-less <))
  (let ((lst1 (sort lst1 test-less))
        (lst2 (sort lst2 test-less)))
    (cond ((or (empty? lst1) (empty? lst2)) (reverse acc))
          ((test-equal (car lst1) (car lst2)) 
           (list-intersect (cdr lst1) (cdr lst2) (cons (car lst1) acc)))
          ((test-less (car lst1) (car lst2))
           (list-intersect (cdr lst1) lst2 acc))
          (else
           (list-intersect lst1 (cdr lst2) acc)))))

(define (common-keys D1 D2 #:test-equal (test-equal =) #:test-less (test-less <))
  (list-intersect (map asc-key D1) (map asc-key D2) #:test-equal test-equal #:test-less test-less))
(common-keys (list (make-asc 1 "one") (make-asc 15 "fifteen"))
             (list (make-asc 15 "fifteen") (make-asc 8 "eight")))
;; '(15)

由@Sylwester改进(仅使用test-less

(define (list-intersect lst1 lst2 (acc '()) #:test-less (test-less <))
  (let ((lst1 (sort lst1 test-less))
        (lst2 (sort lst2 test-less)))
    (cond ((or (empty? lst1) (empty? lst2)) (reverse acc))
          ((test-less (car lst1) (car lst2))
           (list-intersect (cdr lst1) lst2 acc))
          ((test-less (car lst2) (car lst1))
           (list-intersect lst1 (cdr lst2) acc))
          (else
           (list-intersect (cdr lst1) (cdr lst2) (cons (car lst1) acc))))))

(define (common-keys D1 D2 #:test-less (test-less <))
  (list-intersect (map asc-key D1) (map asc-key D2) #:test-less test-less))