删除Racket列表中第n个元素的功能版本

时间:2016-08-19 16:58:17

标签: scheme racket

我想获得一个从原始列表中删除第n个版本的列表。我可以管理以下代码,这是必要的:

(define (list-removeN slist n)
  (define outl '())
  (for ((i (length slist)))
    (when (not (= i n))
      (set! outl (cons (list-ref slist i) outl))))
  (reverse outl))

这可能与功能相当吗?我试过/ list,但我必须插入#f或在那个位置,删除哪个不理想,因为#f或者也可能出现在列表中的其他位置。

2 个答案:

答案 0 :(得分:2)

您可以使用累加器递归执行此操作。像

这样的东西
#lang racket

(define (remove-nth lst n)
  (let loop ([i 0] [lst lst])
    (cond [(= i n) (rest lst)]
          [else (cons (first lst) (loop (add1 i) (rest lst)))])))

(remove-nth (list 0 1 2 3 4 5) 3)
(remove-nth (list 0 1 2 3) 3)
(remove-nth (list 0 1 2) 0)

这会产生

'(0 1 2 4 5)
'(0 1 2)
'(1 2)

您可以使用for/list执行此操作,但由于length调用,此版本会遍历列表两次。

(define (remove-nth lst n)
  (for/list ([i (length lst)]
             [elem lst]
             #:when (not (= i n)))
    elem))

还有split-at,但这可能不会像创建两个列表并附加它们那样最佳。

(define (remove-nth lst n)
  (let-values ([(left right) (split-at lst n)])
    (append left (rest right))))

答案 1 :(得分:2)

典型的滚动您自己的递归实现并使用O(n)时间和O(n)空间。

(define (remove-nth lst i)
  (let aux ((lst lst) (i i))
    (cond ((null? lst) '())       ;; what if (< (length lst) i) 
          ((<= i 0) (cdr lst))    ;; what if (< i 0)
          (else (cons (car lst)
                      (aux (cdr lst) (sub1 i)))))))

使用srfi-1的append-reverse的交互式版本。 O(n)时间和O(1)空间。

(define (remove-nth lst i)
  (let aux ((lst lst) (i i) (acc '()))
    (cond ((null? lst) (reverse acc))               ;; what if (< (length lst) i) 
          ((<= i 0) (append-reverse acc (cdr lst))) ;; what if (< i 0)
          (else (aux (cdr lst) (sub1 i) (cons (car lst) acc))))))