如何在列表中搜索谓词

时间:2014-08-19 14:43:47

标签: scheme

我想创建一个更高阶的函数,它接受一个S-Expr和谓词作为参数,并返回给定s-expression中传递给定谓词的所有原子的列表

例如

(fetch number? '(the (quick 6 fox 8 9) slick 2)) 

并且计划将返回(6 8 9 2)

希望有人能指出我的方向,在家里自己学习

我的开始

(define (fetch pred? ls)
    (cond
        [(null? '())]
        [(number?)]
        [(symbol?)]))

4 个答案:

答案 0 :(得分:2)

这是另一种解决问题的方法。它在处理对时使用累加器而不是append,以消除由append一遍又一遍地重复复制列表结构:

(define (flat-filter pred x)
  (let recur ((x x)
              (initial '()))
    (cond ((null? x) initial)
          ((pair? x)
           (recur (car x) (recur (cdr x) initial)))
          ((pred x) (cons x initial)) ;; the one CONS call per element added
          (else initial))))

这可能是比ÓscarLópez更高级的解决方案,但它可以轻松地抽象出折叠函数(故意选择的参数顺序,以反映大多数Scheme提供的foldfold-right的参数顺序实现作为SRFI 1)的一部分:

(define (flat-fold-right func initial x)
  (cond ((null? x) initial)
        ((pair? x)
         (flat-fold-right func (flat-fold-right func initial (cdr x)) (car x)))
        (else (func x initial)))) ;; the one call to FUNC per element of input

(define (flat-filter pred x)
  (flat-fold-right (lambda (elem res)
                     (if (pred elem)
                         (cons elem res)
                         res))
                   '() x))

奖金免费赠品:

(define (flat-map func x)
  (flat-fold-right (lambda (elem res)
                     (cons (func elem) res))
                   '() x))

(define (flatten x)
  (flat-fold-right cons '() x))

答案 1 :(得分:1)

我们可以使用模板构建一个解决方案,用于遍历列表列表,在构建它们的同时处理展平结果。例如,这是解决问题的一种方法:

(define (fetch pred lst)
  (cond ((null? lst) '())  ; if the list is empty, return the empty list
        ((not (pair? lst)) ; if the current element is an atom
         (if (pred lst)    ; then test it using the predicate
             (list lst)    ; if the condition holds, add the current element to result
             '()))         ; otherwise ignore the current element
        (else (append (fetch pred (car lst))     ; recursive step: traverse both the car
                      (fetch pred (cdr lst)))))) ; and the cdr part of the list

以上是您如何从头开始编写解决方案。然而,在惯用方案中,它建议将问题分成较小的部分并使用现有的程序(或编写一般的,可重复使用的程序)并组成它们以形成答案。例如,在Racket中我们可以这样做:

; test if an object is an atom
(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))

 ; map over a list of lists    
(define (map* func lst)
  (if (atom? lst)
      (func lst)
      (map (curry map* func) lst)))

; "fetch" by first mapping and then flattening the input list
(define (fetch pred lst)
  (flatten
   (map* (lambda (x) (if (pred x) x '()))
         lst)))

或者,我们也可以先flatten然后filter,如@ user448810所示。无论如何,结果如预期:

(fetch number? '(the (quick 6 fox 8 9) slick 2))
=> '(6 8 9 2)

答案 2 :(得分:1)

最容易将问题分成两部分。

一个传统上称为flatten的过程从列表中删除所有嵌套;因此,(flatten '(the (quick 6 fox 8 9) slick 2))将返回(the quick 6 fox 8 9 slick 2)

传统上称为filter的第二个过程然后扫描flatten的输出并仅返回通过谓词的那些项;因此(filter number? (flatten '(the (quick 6 fox 8 9) slick 2)))将返回(6 8 9 2)

这意味着您可以编写(define (fetch pred? ls) (filter pred? (flatten ls)))来定义您的功能。

我会留给你写flattenfilter。两者都很简单,并且在其他情况下都比你的问题更有用。您应该在标准工具包中使用这两个工具包; I do

答案 3 :(得分:1)

此解决方案适用于所有数据类型。它需要跟随汽车和cdr时使用回溯列表。

(define (filter-tree pred? tree)
  (reverse
   (let loop ((acc '()) (tree tree) (back '()))
     (cond ((pred? tree) (cons tree acc))
           ((not (pair? tree)) 
            (if (null? back) acc (loop acc (car back) (cdr back))))
           ((pred? (car tree)) 
            (loop (cons (car tree) acc) (cdr tree) back))
           ((pair? (car tree)) 
            (loop acc (car tree) (cons (cdr tree) back)))
           (else (loop acc (cdr tree) back))))))

;; test data
(define sub '(quick 6 fox 8 9))
(define end '(slick 2))
(define lst `(the ,sub ,@end))

;; tests    
(filter-tree number? lst) ; ==> (6 8 9 2)
(filter-tree (lambda (x) (equal? x lst)) lst) ; ==> ((the (quick 6 fox 8 9) slick 2))
(filter-tree (lambda (x) (or (equal? x sub) (equal? x end))) lst) ; ==> ((quick 6 fox 8 9) (slick 2))
(filter-tree (lambda (x) (equal? x end)) lst) ; ==> ((slick 2))