【问题标题】:Intersect more lists in Scheme与 Scheme 中的更多列表相交
【发布时间】:2013-04-06 12:56:15
【问题描述】:

我正在尝试与 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) (?game air-hockey)) 相同的(?x john),因此在我的新结果列表中,第一个列表将如下所示:((?x john) (?city new-york) (?game air-hockey))。按照第二个列表的模式,我将得到((?x mike) (?city chicago) (?game tennis)),我的新结果列表将是:

(((?x john) (?city new-york) (?game air-hockey))  
 ((?x mike) (?city chicago) (?game tennis)))

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

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

【问题讨论】:

    标签: list scheme racket intersection


    【解决方案1】:

    我知道你必须用列表来解决这个问题,我不会写一个列表实现,因为它很麻烦(它不是最适合这项工作的数据结构),相反我会告诉你如何解决在 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)))
    

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

    【讨论】:

    • 感谢您的回答。我想我必须为联合和交集编写自己的函数,但这似乎并不难。我还假设 set-first 和 set-rest 是 car 和 cdr 的等价物。
    • 没错。不过,算法将是相同的——这才是最重要的。干杯!
    【解决方案2】:

    我会先改进您的描述。 (?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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-20
      • 2022-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-20
      • 1970-01-01
      相关资源
      最近更新 更多