Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 球拍/方案-用非平面列表中的另一个元素替换项目_List_Recursion_Replace_Scheme_Racket - Fatal编程技术网

List 球拍/方案-用非平面列表中的另一个元素替换项目

List 球拍/方案-用非平面列表中的另一个元素替换项目,list,recursion,replace,scheme,racket,List,Recursion,Replace,Scheme,Racket,当给出一个列表时,我试图用另一个项目替换一个项目。我已经编写了一个程序,可以为平面列表执行此操作,但我不确定当列表不是平面列表时如何实现它。 这是替换程序的当前代码: (define repl (lambda (exp1 exp2 exp3) (cond ((null? exp3) exp3) ((equal? (first exp3) exp1) (cons exp2 (repl exp1 exp2 (rest exp3)))) (else (c

当给出一个列表时,我试图用另一个项目替换一个项目。我已经编写了一个程序,可以为平面列表执行此操作,但我不确定当列表不是平面列表时如何实现它。 这是替换程序的当前代码:

(define repl
  (lambda (exp1 exp2 exp3)
    (cond
      ((null? exp3) exp3)
      ((equal? (first exp3) exp1) (cons exp2 (repl exp1 exp2 (rest exp3))))
      (else (cons (first exp3) (repl exp1 exp2 (rest exp3)))))))
我是一个非常新的编码在球拍,所以我不知道我将如何才能应用这个当它不是一个平面列表 有效的测试用例如下所示

(repl 'a 'b '((f a) (f (a)))) => '((f b) (f (b)))
但当我运行当前的过程时,它会生成

'((f a) (f (a)))

我将如何应用我的当前代码来处理非平面列表?

您需要考虑递归中的新情况:如果列表中的当前元素是另一个列表,该怎么办?在这种情况下,我们需要进行更深层次的递归,并向下遍历当前元素和列表的其余部分。否则,请检查当前元素是否需要更换,或者不使用它。这就是我的意思,注意,当我们只想替换原子时,这是一个更快的解决方案:

(define repl
  (lambda (exp1 exp2 exp3)
    (cond
      ; base case: list is empty
      ((null? exp3) exp3)
      ; base case: current element is an atom
      ((not (pair? exp3))
       ; should we replace current element?
       (if (equal? exp3 exp1) exp2 exp3))
      ; recursive case: current element is a list
      (else
       ; recursively descend over both sublists
       (cons (repl exp1 exp2 (first exp3))
             (repl exp1 exp2 (rest exp3)))))))
无论要替换的元素嵌套得有多深,它都能按预期工作:

(repl 'm 'x '((a (b (c (d e (f (m))) h) i (j) (k (l (m)))) n) o (p)))
=> '((a (b (c (d e (f (x))) h) i (j) (k (l (x)))) n) o (p))
编辑:现在,如果要替换的元素是列表本身,我们必须在条件周围移动。下面是实现,它比我以前的解决方案更通用,但也更慢。感谢@amalloy提出这种方法:

(define (repl exp1 exp2 exp3)
  (cond ; base case: list is empty
        ((null? exp3) exp3)
        ; base case: current element is the one we're looking for
        ((equal? exp1 exp3) exp2)
        ; recursive case: current element is a list
        ((pair? exp3) (cons (repl exp1 exp2 (first exp3)) 
                            (repl exp1 exp2 (rest exp3))))
        ; base case: current element is not the one we're looking for
        (else exp3)))
例如:

(repl '(f (g)) 'x '((a (b (c (d e (f (g))) h) i (j) (k (l (m)))))))
=> '((a (b (c (d e x) h) i (j) (k (l (m))))))
试试这个:

(define replace
  (lambda (x y l)
    (fold-right (lambda (e acc)
                  (if (pair? e)
                      (cons (replace x y e) acc)
                      (cons (if (eq? e x) y e) acc)))
                '()
                l)))

我建议在测试一对之前先测试相等性。使用您当前的解决方案,不可能用另一个列表替换一个列表。@amalloy这比这个要复杂一些。我更新了我的答案,但你能想出一个更简单的方法吗?其实并不复杂。我不想创造一个答案,只是“你的,但更简单”,所以请看。如果你不替换,你只需要关心倦怠,只需要关心基本情况下的平等。@amalloy天哪,这太简单了!谢谢你的建议,如果你不介意的话,我会把它添加到这个答案中,当然我想如果我们真的想优化,我们会编写递归部分的两个不同版本,其中cond子句的顺序不同。然后,在开始递归之前,检查要替换的项是否是列表,并使用适当的lambda进行递归。
repl
是个坏名字,因为它代表“read-eval-print-loop”,可能会模棱两可。map不是更相关吗,因为你总是在折叠中考虑结果?@amalloy-yes,使用
map
它可以工作,
cons
-es在map内隐式移动。所以,没错,不错!使用
equal?
可能更安全。此外,正如@amalloy在我最初的回答中指出的,这不适用于替换列表。这种通用方法确实适用于替换列表,就像您的方法一样:您只需(再次)交换相等测试和成对测试的顺序。