【问题标题】:Generating list of 2-lists in Scheme在 Scheme 中生成 2 个列表的列表
【发布时间】:2011-02-20 16:11:51
【问题描述】:
(define cart-product
  (lambda (sos1 sos2)
    (if (null? sos1) '()
      (cons
       (cart-prod-sexpr (car sos1) sos2)
       (cart-product (cdr sos1) sos2)))))

(define cart-prod-sexpr
  (lambda (s sos)
    (if (null? sos) '()
        (cons
         (list s (car sos))
         (cart-prod-sexpr s (cdr sos))))))

调用(cart-product '(q w) '(x y)) 产生(((q x) (q y)) ((w x) (w y)))

我怎样才能生成((q x) (q y) (w x) (w y))

【问题讨论】:

    标签: list scheme cartesian-product


    【解决方案1】:

    获胜的高阶函数。 Haskell 的列表理解转换为 Scheme 以获得更好的解决方案:

    ; cart xs ys = [ [x,y] | x <- xs, y <- ys ]
    (define (cart xs ys)
      (let ((f (lambda (x) (map (lambda (y) (list x y)) ys))))
        (concatenate (map f xs))))
    
    (cart '(a b c) '(x y)) => ((a x) (a y) (b x) (b y) (c x) (c y))
    

    它以 m*n (m = |xs|, n = |ys|) 运行。连接来自 SRFI-1。

    【讨论】:

    • 不应该在 mnn 中运行吗?您生成 m 个长度为 n 的列表,然后连接必须遍历每个列表以找到在何处附加下一个列表的头部。紧凑代码仍然是 +1。
    • 优秀的解决方案。虽然我花了一个多小时才弄清楚机械原理。解决方案首先定义了名为 let 绑定 f ,它接受 x 的每个元素并生成一个 2 列表的列表。 (map f xs) 对 xs 的每个元素执行 f 以生成 Listof(ListOf(2-Lists))。通过调用 concatenate 函数,该列表被展平为 ListOf(2-List)。我希望我的理解是正确的。
    【解决方案2】:

    未经测试。请注意,我定义的append-list 过程实际上返回一个以sos2 结尾的列表。这在这里是合适的(也是正确的做法),但不是普遍的。

    (define cart-product
      (lambda (sos1 sos2)
        (if (null? sos1) '()
          (append-list
           (cart-prod-sexpr (car sos1) sos2)
           (cart-product (cdr sos1) sos2)))))
    
    (define cart-prod-sexpr
      (lambda (s sos)
        (if (null? sos) '()
            (cons
             (list s (car sos))
             (cart-prod-sexpr s (cdr sos))))))
    
    (define append-list
      (lambda (sos1 sos2)
        (if (null? sos1) sos2
          (cons
            (car sos1)
            (append-list (cdr sos1) sos2)))))
    

    请注意,如果列表大小为 n,则生成大小为 O(n2) 的列表需要时间 O(n3)。 使用常规的append 会花费 O(n4)。 我只是在没有意识到的情况下实现了常规的append 如果你愿意要采取 O(n2) 你必须更聪明。就像在这个未经测试的代码中一样。

    (define cart-product
      (lambda (sos1 sos2)
        (let cart-product-finish
          (lambda (list1-current list2-current answer-current)
            (if (null? list2-current)
              (if (null? list1-current)
                 answer-current
                 (cart-product-finish (car list1-current) sos2 answer-current))
              (cart-product-finish list1-current (car sos2)
                (cons (cons (cdr list1-current) (cdr list2-current)) answer-current))))
        (cart-product-finish list1 '() '())))
    

    如果我有错误,我的想法是递归循环第一个和第二个元素的所有组合,每个组合都将 answer-current 替换为 cons 一个更多组合,然后是我们的其他所有组合已经找到了。多亏了尾调用优化,这应该是有效的。

    【讨论】:

    • 对不起,您的解决方案解决了问题,但它非常复杂。在其他语言中,您使用 2 个嵌套循环。在 Scheme 中有 named let.
    • @knivil:有没有一个更简单但同样有效的解决方案? (我打算稍微简化一下这个,但我不认为它可以在不牺牲效率的情况下进一步简化。)
    【解决方案3】:

    在我的头顶:

    (define cart-product
      (lambda (sos1 sos2)
        (if (null? sos1) 
            '()
            (append
             (cart-prod-sexpr (car sos1) sos2)
             (cart-product (cdr sos1) sos2)))))
    

    【讨论】:

      【解决方案4】:
      (reduce #'append 
                 (mapcar #'(lambda(x)
                               (mapcar #'(lambda(y) 
                                             (list x y))
                                '(a b c))) 
                 '(1 2 3)))
      

      => ((1 A) (1 B) (1 C) (2 A) (2 B) (2 C) (3 A) (3 B) (3 C))

      [注意:解决方案是针对 Common Lisp (CLisp) 而不是 Scheme,但我想它应该在 Scheme 中非常相似]

      外部 (reduce #'append ) 用于替换 knivil 在解决方案中给出的 (concatenate (map )

      但是,与其他解决方案相比,我不确定我的解决方案在性能参数上的表现如何。有人可以对此发表评论吗?

      【讨论】:

        【解决方案5】:

        这里只是针对同一问题的不同解决方案。我认为这很容易理解,也许会对某人有所帮助。

        (define (cart-product l1 l2)
          (define (cart-product-helper l1 l2 org_l2)
            (cond
              ((and (null? l1)) `())
              ((null? l2) (cart-product-helper (cdr l1) org_l2 org_l2))
              (else (cons (cons (car l1) (car l2)) (cart-product-helper l1 (cdr l2) org_l2)))
            )
          )
          (cart-product-helper l1 l2 l2)
        )
        

        【讨论】:

          猜你喜欢
          • 2015-11-30
          • 1970-01-01
          • 2017-03-06
          • 2019-10-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-20
          相关资源
          最近更新 更多