Recursive sublist? function

你。 提交于 2019-12-12 03:07:12

问题


I can't seem to figure how to write a correct uscheme (A derivative of MIT Scheme) function that will return boolean whether a list contains a smaller list.

I wrote this.

(define sublist? (xs ys)
    (if (= xs '())
        #t
        (if (= ys '())
            #f
            (if (= (car xs) (car ys))
                (sublist? (cdr xs) (cdr ys))
                (sublist? xs (cdr ys))
            )
        )
    )
)

It passes most of my test cases except this one test case.

(sublist? '(a b c) '(1 2 a 3 b 4 c 5 6))
;; this returns true while it's supposed to return false

Test case requires that sublist is consecutive with no random element in between.

I'm a bit stuck on how to correct this. Does anyone else have an idea?


回答1:


The problem is that your algorithm is too eager—once it finds two elements that are equal, it immediately throws away that element and keeps checking. In actuality, finding two equal elements is not enough, since your algorithm might have to backtrack if it finds an incomplete match.

The easiest way to represent this sort of algorithm would be with a helper function that determines if a sublist matches at a given position in the list. The sublist? function would then iterate through each position in the larger list looking for matches.

Here's my implementation:

(define (sublist? xs ys)
  (define (sublist-equal? xs ys)
    (cond
      ((null? xs) #t)
      ((null? ys) #f)
      ((equal? (car xs) (car ys))
       (sublist-equal? (cdr xs) (cdr ys)))
      (else #f)))
  (cond
    ((null? xs) #t)
    ((null? ys) #f)
    ((sublist-equal? xs ys) #t)
    (else (sublist? xs (cdr ys)))))

Note the internal sublist-equal? helper function.

I also use cond instead of nested if expressions, since cond should really be used in this case to represent this sort of logic. Furthermore, I use equal? instead of =, since it most Schemes I know of, = is for numeric comparison (yours might be different, I don't know).




回答2:


Here's my version "without a helper function". It does use two nested loops, though:

(define (sublist? needle haystack)
  (if (null? needle)
      #t
      (let ((first (car needle)))
        (let outer ((cur haystack))
          (define (next)
            (outer (cdr cur)))
          (cond ((null? cur) #f)
                ((eqv? (car cur) first)
                 (let inner ((lhs (cdr needle))
                             (rhs (cdr cur)))
                   (cond ((null? lhs) #t)
                         ((null? rhs) (next))
                         ((eqv? (car lhs) (car rhs))
                          (inner (cdr lhs) (cdr rhs)))
                         (else (next)))))
                (else (next)))))))



回答3:


(define sublist? (xs ys)
  (cond ((= xs '()) #t)  ;;cond easier to read than 
        ((= ys '()) #f)  ;;nested if statements
        ((and (= (car xs) (car ys)) 
 ;;need to check for more than singleton match
              (or (null? (cdr xs))
                  (and (not (null? (cdr ys)))
                       (= (cadr xs) (cadr ys))
                       (sublist? (cdr xs) (cdr ys)))))) ;not tail call
  ;;this cond clause has no second part, 
  ;;the first will return #t or #f
  ;;will backtrack if #f is propagated up the stack.
         (else (sublist? xs (cdr ys)))) ; tail call


来源:https://stackoverflow.com/questions/28776363/recursive-sublist-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!