计算方案中列表中的零个数

时间:2016-10-18 19:21:08

标签: list scheme racket

(define (num-zeroes lst)
(define (helper lst sofar)
 (cond ((null? lst) sofar)
    ((list? (car lst)) (helper (car lst) sofar))
    ((eq? lst 0) (helper (cdr lst) (+ 1 sofar)))
    (else
     (helper (cdr lst) sofar))))
(helper lst 0))

此函数用于计算列表中的0数。但是,当我输入值时,它一直给我0。我怎么能解决这个问题?

1 个答案:

答案 0 :(得分:1)

在第三种情况下,您要将lst与0进行比较。这应该是(car lst)

由于您的(list? (car lst))条件,您似乎想要计算嵌套列表。在当前实现中存在此问题(上面的检查已修复),因为条件不会添加列表的单独部分。

如,

(num-zeroes '(0 0 (1 0) (1 0 0))) ; => 3

要解决此问题,您可以执行以下操作:

(define (num-zeroes lst)
  (define (helper lst sofar)
    (cond ((null? lst) sofar)
          ((list? (car lst)) (+ sofar                        ;; add sofar to
                                (helper (car lst) 0)         ;; branched out first part
                                (helper (cdr lst) 0)))       ;; and branched rest
          ((eq? (car lst) 0) (helper (cdr lst) (+ 1 sofar))) ;; (car lst), not lst
          (else
           (helper (cdr lst) sofar))))
  (helper lst 0))

这导致:

(num-zeroes '(0 0 (1 (1 (0 0) 0)) (1 0 0)))  ;; => 7

现在,您希望在集合中执行某些操作并保持累积值的问题会发生很多变化。 fold是一个高阶函数,专门针对这些问题而设计。

Fold采用带有两个参数(元素和累加器),起始值和集合的函数。它连续将函数应用于集合的每个元素,最后返回累加器。

在您的情况下,当元素为0时,可以仅向累加器添加1,并将展平列表(flatten从列表中删除嵌套)传递给foldl(请参阅https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._foldl%29%29)(l表示它从 l eft到右侧)列表处理嵌套:

(define (num-zeroes2 lst)
  (foldl (lambda (e acc)
           (if (= e 0)
               (+ acc 1)
               acc))
         0
         (flatten lst)))

这导致相同的结果:

(num-zeroes2 '(0 0 (1 (1 (0 0) 0)) (1 0 0))) ;; => 7

或者,考虑一下,你也可以flatten列表和filter所有值等于0(有一个名为zero?的库方法),并计算元素:

(define (num-zeroes3 lst)
  (length
   (filter zero? (flatten lst))))

希望这有帮助。