Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/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 Scheme Guile:仅从列表中删除第一个匹配项(非破坏性)_List_Scheme_Guile - Fatal编程技术网

List Scheme Guile:仅从列表中删除第一个匹配项(非破坏性)

List Scheme Guile:仅从列表中删除第一个匹配项(非破坏性),list,scheme,guile,List,Scheme,Guile,我需要以非破坏性的方式从列表中删除元素的第一次出现 根据,有一组函数可以以破坏性的方式执行此操作(delq1!、delv1!、delete1!)。另一方面,非破坏性版本将删除元素的所有引用 我知道我可以写一个函数(可能是通过过滤器)在几行内完成,但我想知道是否有更好的/标准的方法来完成 举个例子,给出清单 ((1 2) (3 4) (1 2)) 移除元件时 (1 2) 我希望结果是好的 ((3 4) (1 2)) 而原来的名单仍然存在 ((1 2) (3 4) (1 2)). 提前

我需要以非破坏性的方式从列表中删除元素的第一次出现

根据,有一组函数可以以破坏性的方式执行此操作(delq1!、delv1!、delete1!)。另一方面,非破坏性版本将删除元素的所有引用

我知道我可以写一个函数(可能是通过过滤器)在几行内完成,但我想知道是否有更好的/标准的方法来完成

举个例子,给出清单

((1 2) (3 4) (1 2)) 
移除元件时

(1 2) 
我希望结果是好的

((3 4) (1 2)) 
而原来的名单仍然存在

((1 2) (3 4) (1 2)).

提前谢谢

在Scheme中,标准解决方案是创建一个新列表,但不包含元素。在中,我们看到
delete
过程消除了元素的所有出现-因此我们必须推出自己的解决方案,但很简单:

(define (delete-1st x lst)
  (cond ((null? lst) '())
        ((equal? (car lst) x) (cdr lst))
        (else (cons (car lst)
                    (delete-1st x (cdr lst))))))
例如:

(delete-1st '(1 2) '((1 2) (3 4) (1 2)))
=> '((3 4) (1 2))

这里有五个版本的
delete1
和一个版本的
delete1。每个元素从返回的列表中删除第一个与给定元素相等的元素。后者在时间和空间上更为理想。不使用破坏性功能,除非在最后一部分中考虑了其正确使用

第一种是非尾部递归:

(define (delete1a v l) 
  (let loop ((l l))
    (if (null? l) '()
        (if (equal? v (car l)) 
            (cdr l)
            (cons (car l) (loop (cdr l)))))))
然后,第二个和第三个是尾部递归的,但效率低下,因为它们复制的内容超出了需要。例如,如果未找到该项,则复制整个列表

 (define (delete1b v l)
   (let loop ((l l) (a '()))
     (if (null? l) (reverse a)
         (if (equal? v (car l)) 
             (append (reverse a) (cdr l))
             (loop (cdr l) (cons (car l) a))))))
第三个包含
(追加(反向l)m)
的融合,当到达列表末尾时删除无用的
(反向a)
,但它仍然在
a
中累积该
(反向a)
所需的列表副本:

在第四种版本中,累加器由计数器代替:

(define (delete1d v ls)
   (let loop ((l ls) (a 0))
     (if (null? l) ls
         (if (equal? v (car l)) 
             (append (take ls a) (cdr l))
             (loop (cdr l) (+ a 1))))))
take
以递归方式实现时,它必须反转其结果,但我们已经有了一个
append reverse
,那么为什么不使用一个
take reverse
以相反的顺序返回其结果呢?因此
(append(take a b)c)
(append(reverse(take reverse a b))c)替换,然后被
(附加反向(取反向a b)c)

这样做的结果是,列表被遍历一次,如果没有找到值,并且如果在元素被遍历和复制两次之前只找到了列表的前缀,则不进行复制。在
中执行一次反向操作
,然后在
中执行一次追加反向操作

如果允许使用破坏性函数,则可以使用
追加反向!
而不是
追加反向
将列表前缀的复制安全地减少到一次,如
(追加反向(取反向ls a)(cdr l))
中所述
(取反向ls a)
的结果是
线性使用的副本(追加反向r(cdr l))
。有一些类型的系统可以证明这是安全的:

(define (append-reverse! l m) 
  (if (null? l)
      m
      (let ((next (cdr l)))
        (begin (set-cdr! l m)
               (append-reverse next l)))))
但我们可能会更进一步,定义
delete1!

(define (delete1! v l)
  (let loop ((left '()) (right l))
    (if (null? right) l
        (if (equal? (car right) v) 
            (if (null? left) (cdr right)
                (begin (set-cdr! left (cdr right)) 
                       l))
            (loop right (cdr right))))))

这只会遍历列表一次,不会进行复制。

您的解决方案在某个地方缺少一个
cons
。无论如何,OP想知道是否有一种内置的方法来实现它,但实际上没有。:-(太好了!它很有效!非常感谢!为了完成这篇文章,我只想指出在示例中它应该是(delete-1st'(1-2) '((1 2) (3 4) (1 2)))
(define (append-reverse! l m) 
  (if (null? l)
      m
      (let ((next (cdr l)))
        (begin (set-cdr! l m)
               (append-reverse next l)))))
(define (delete1! v l)
  (let loop ((left '()) (right l))
    (if (null? right) l
        (if (equal? (car right) v) 
            (if (null? left) (cdr right)
                (begin (set-cdr! left (cdr right)) 
                       l))
            (loop right (cdr right))))))