如何在lisp中使用嵌套循环进行配对

问题描述:

我正在尝试在lisp中配对功能。对函数得到2个输入然后使对彼此作出一个列表。这是我的代码。如何在lisp中使用嵌套循环进行配对

(defun npair (s1 s2) 
    (let ((result '())) 
    (cond ((null s1) s2) 
      ((null s2) s1) 
      (t (loop 
       (when (null s1) (return result)) 
       (while (not (null s2)) 
       (setq result (cons (list (car s1) (car s2)) result)) 
       (setq s2 (cdr s2))) 
       (setq s1 (cdr s1))))))) 

这个功能应该已经返回像(npair '(a b c) '(1 2)) - >((a 1) (a 2) (b 1) (b 2) (c 1) (c 2))

但我的结果只有((a 1) (a 2))。 请帮忙!!

+0

WHILE未知​​,您的代码无法运行。 –

+0

您的'null'情况意味着这不是一个正确的笛卡儿积。如果任一列表为空,则结果必须为空:因为非空列表的每个元素与空列表的每个元素的组合都是空的。当然,我们可以定义一个我们喜欢的功能;如果它输出无偿*特设*特殊情况,它不太可能有用。 – Kaz

如果你希望积累在外环在一个内部循环值(S),你可能会更好过简单累加的数值,而不是试图通过突变变量来做到这一点:

(loop for e1 in p1 
    append (loop for e2 in p2 
      collect (list e1 e2))) 

你的格式也没问题,习惯是不把新的括号放在新行上。

使用从上面的循环结构,你的整个功能因此将是:

(defun npair (p1 p2) 
    (loop for e1 in p1 
     append (loop for e2 in p2 
       collect (list e1 e2)))) 

好的,简单和相当的可读性。

从它的外表来看,你希望的结果叫做笛卡尔积

我在Scheme编程语言中使用的实现是这样的:

(define (product . args)                
    (if (null? args)                 
     (list '())                  
     (apply append                 
       (map (lambda (rest)              
        (map (lambda (first)            
          (cons first rest))          
          (car args)))            
        (apply product (cdr args)))))) 

例如,下面是一个使用切斯计划输出:

> (product '(a b c) '(1 2)) 
((a 1) (b 1) (c 1) (a 2) (b 2) (c 2)) 

当其他人表现出你最好的选择为了达到你想要的结果而不是你的实现,下面是你的实现不起作用的原因:你将s2的值更改为null,同时将的第一个元素在处理s1的其余元素之前,不会恢复原始值s2。 (这是多好的一个原因,你应该循环输入值,而不在首位变异他们。)

这里有一个版本的实现有什么实际工作,因为它不发生变异的输入:

(defun npair (s1 s2) 
    (let ((result '())) 
    (cond ((null s1) s2) 
      ((null s2) s1) 
      (t (loop for e1 in s1 
       do (loop for e2 in s2 
         do (push (list e1 e2) result))) 
      (nreverse result)))))