在Scheme中交叉更多列表

时间:2013-04-06 12:56:15

标签: list scheme racket intersection

我想在Scheme中交叉更多列表,我需要一些帮助。列表如下所示:

前两个:

(((?x john) (?city new-york))  
 ((?x mike) (?city chicago))  
 ((?x mary) (?city london)))

(((?city chicago))     
 ((?city new-york)))

我需要查看第一个列表中的每个列表(比如A)并查看第二个列表中是否有列表(比如说B),这样A至少有一个与B共有的元素。如果没有这样的元素,结果列表将不包含A.上面提到的两个列表的结果将是:

(((?x john) (?city new-york))  
 ((?x mike) (?city chicago)))

因为列表((?x mary) (?city london))(((?city chicago) ((?city new-york)))中的任何列表没有任何共同之处。

现在结果列表必须与下一个列表相交:

(((?x mike) (?game tennis))  
 ((?x john) (?game air-hockey)))

结果列表中的第一个列表((?x john) (?city new-york))(?x john)((?x john) (?game air-hockey))具有共同点,因此在我的新结果列表中,第一个列表将如下所示:{{1} }。按照第二个列表的这个模式,我将获得((?x john) (?city new-york) (?game air-hockey)),我的新结果列表将是:

((?x mike) (?city chicago) (?game tennis))

这意味着,对于至少有一个共同元素的每两个列表,我必须进行重聚并将其添加到新的结果列表中。

现在我的问题是,你能给我一点帮助,在Scheme中实现这个吗?我不想要代码,只需要关于我应该使用哪些函数的一些想法:)。

2 个答案:

答案 0 :(得分:2)

我知道你必须用列表来解决这个问题,我不会写一个列表实现,因为它很麻烦(它不是作业的最佳数据结构),而是我会告诉你如何解决这个问题。在Racket的设置操作方面存在问题,因此您可以将其翻译为使用列表。首先,表示数据:

(define s1 (set (set '(?x john) '(?city new-york))
                (set '(?x mike) '(?city chicago))
                (set '(?x mary) '(?city london))))

(define s2 (set (set '(?city chicago))
                (set '(?city new-york))))

(define s3 (set (set '(?x mike) '(?game tennis))
                (set '(?x john) '(?game air-hockey))))

在表示到位的情况下,我们需要一个给定单个数据的过程,如果它与数据列表共享一些共同的元素 - 如果它找到一个匹配,它返回数据的并集,如果它没有找到任何它返回#f

(define (find-match one-set set-of-sets)
  (cond ((set-empty? set-of-sets)
         #f)
        ((not (set-empty? (set-intersect one-set (set-first set-of-sets))))
         (set-union one-set (set-first set-of-sets)))
        (else
         (find-match one-set (set-rest set-of-sets)))))

例如:

(find-match (set '(?x mike) '(?city chicago))
            (set (set '(?x mike) '(?game tennis))
                 (set '(?x john) '(?game air-hockey))))

=> (set '(?x mike) '(?city chicago) '(?game tennis))

现在编写一个程序可以很容易地将一组数据中的所有元素与另一组数据重复匹配:

(define (join s1 s2)
  (let loop ((s1 s1)
             (result (set)))
    (if (set-empty? s1)
        result
        (let ((match (find-match (set-first s1) s2)))
          (if match
              (loop (set-rest s1) (set-add result match))
              (loop (set-rest s1) result))))))

例如,s1s2之间的第一场匹配(如上所述)将如下所示:

(join s1 s2)

=> (set (set '(?x mike) '(?city chicago))
        (set '(?x john) '(?city new-york)))

要查找多组数据之间的连续匹配,只需根据需要多次调用join,每组数据,累积结果:

(define (join-all . data)
  (if (empty? data)
      (set)
      (foldr join (first data) (rest data))))

(join-all s1 s2 s3) ; equivalent to (join (join s1 s2) s3)

=> (set
     (set '(?x john) '(?city new-york) '(?game air-hockey))
     (set '(?x mike) '(?city chicago)  '(?game tennis)))

如您所见,最终结果是我们期望的结果。

答案 1 :(得分:0)

我首先要改进你的描述。 (?x john)不是list,而是query。并且((?x john) (?city new-york))不是列表列表,它是proposition(??)。并且

(((?x john) (?city new-york))  
 ((?x mike) (?city chicago))  
 ((?x mary) (?city london)))

不是列表列表,而是set of propositions

一旦你开始明确地描述事物,你就可以开始在实体上定义一些操作:

query_match
query_has_variable
proposition_has_query
proposition_extend
etc