在Racket中对列表进行细分

时间:2015-04-17 23:22:55

标签: list function scheme racket

我想在Scheme中创建一个函数,使一个列表中的子列表以一种我可以给出一个值来启动细分的方式,一个值来阻止它,如下所示:

(function '(1 2 3 1 4 5 6 3) 1 3)
>'((1 2 3) (1 4 5 6 3))

我找不到一个正确的方法,因为你可以看到该函数会以1开始一个子列表并以3结束它,我该如何实现这样的东西?

2 个答案:

答案 0 :(得分:1)

这是非贪婪的,因此它会得到最短的答案(在遇到开始后在第一个终点停止)并继续在最后一个结束位置之后寻找匹配。它是一个自己的解决方案,没有花哨的列表程序,但它也是尾递归。

(define (sublist src start end)
  (let loop ((lst src) (acc #f) (results '()))
    (cond 
      ((null? lst) (reverse results)) ; remove reverse if the order of matches isn't an issue
      ((not acc) (loop (cdr lst) (if (eqv? (car lst) start) (list (car lst)) #f) results))
      ((not (eqv? (car lst) end)) (loop (cdr lst) (cons (car lst) acc) results))
      (else (loop (cdr lst) #f (cons (reverse (cons (car lst) acc)) results))))))


(sublist '(1 2 1 3 2 2 2 2 2) 1 2) ; ==> ((1 2) (1 3 2))
(sublist '(1 2 3 1 4 5 6 3 1 4 8 7 9 5) 4 5) ; ((4 5) (4 8 7 9 5))

要查找重叠结果,可能会有效:

(define (sublist-full src start end)
  (let loop ((lst src) (acc #f) (backtrack #f) (results '()))
    (if (null? lst)
        (if backtrack 
            (loop backtrack #f #f results)
            (reverse results))
        (let ((a (car lst)))
          (if acc
              (cond ((and (eqv? a start) (not backtrack)) (loop (cdr lst) (cons a acc) lst results))
                    ((eqv? a end) (loop (cdr lst) (cons a acc) backtrack (cons (reverse (cons a acc)) results)))
                    (else (loop (cdr lst) (cons a acc) backtrack results)))
              (if (eqv? a start)
                  (loop (cdr lst) (cons a '()) #f results)
                  (loop (cdr lst) #f #f results)))))))

(sublist-full '(1 2 1 3 2 2 2 2 2) 1 2) 
; ==> ((1 2) (1 2 1 3 2) (1 2 1 3 2 2) (1 2 1 3 2 2 2) 
;      (1 2 1 3 2 2 2 2) (1 2 1 3 2 2 2 2 2) (1 3 2) 
;      (1 3 2 2) (1 3 2 2 2) (1 3 2 2 2 2) (1 3 2 2 2 2 2))

答案 1 :(得分:1)

这是我能想到的最好的 - 无疑是更优雅的方式。

我们的想法是放弃所有内容,直到找到" start"价值,然后保持一切,直到"停止"值(如果有的话),然后递归剩余的列表。

#lang racket
(require srfi/1) ; For drop-while

(define (subdiv ls start stop)
  (let ([part-one (drop-while (lambda (x) (not (= x start))) ls)])
    (let-values ([(main rest) (splitf-at part-one (lambda (x) (not (= x stop))))])
      (if (null? rest)         ; empty means the stop value wasn't found
          '()
          (cons (append main (list stop)) 
                (subdiv (cdr rest) start stop))))))

示例:

> (subdiv '(3 4 5 1 111 1 1 1 2 2 3 1 2) 1 2)
'((1 111 1 1 1 2) (1 2))
> (subdiv '(3 4 5 1 2 3 1 2) 1 2)
'((1 2) (1 2))
> (subdiv '(1 2) 1 2)
'((1 2))
> (subdiv '(1) 1 2)
'()
>