方案:使用递归计数类型

时间:2014-06-03 05:23:24

标签: recursion racket accumulator

结构定义:

(define-struct movie (title genre stars))
;; title is a nonempty string
;; genre is a nonempty string
;; stars us a list of nonempty strings

我正在尝试编写一个消耗电影列表的方案函数,并生成最常出现的类型。

到目前为止,我有以下内容:

(define (popular-gnere movies)
(local
[(define acc movies genre)
(cond
[(empty? movies) genre]
[(equal? genre (movie-genre (first movies)))
(acc (rest movies genre)))

我很难理解如何计算特定类型在特定电影列表中出现的次数。 我知道在这种情况下累积的递归效率最高,但是在完成累加器时遇到了麻烦。

2 个答案:

答案 0 :(得分:0)

为什么不修复括号问题并正确缩进代码。按 CRTL + i 。如果标识错误,您可能缺少括号。按运行进行评估,您将收到正确的错误消息。如果您的某些内容不会产生错误,请更新此问题。

您的问题的答案是您向本地程序添加的参数多于全局。这样你就可以获得一个参数,当你在当前的element.eg中找到search元素时,该参数可以保存你增加的计数。

(define (length lst)
  (define (length-aux lst cnt)
    (if (null? lst)
        cnt
        (length-aux (cdr lst) (add1 cnt))))
  (length-aux lst 0))

或更好的名为let

(define (length lst)
  (let length-aux ((lst lst) (cnt 0))
    (if (null? lst)
        cnt
        (length-aux (cdr lst) (add1 cnt)))))

修改

我建议至少有4个辅助程序来解决每个问题。 (如果您使用球拍自己的removecountargmax,则会减少。请注意,可能还有很多其他方法可以解决这个问题,但这就是我在没有哈希表的情况下解决它的方法。

由于你只对流派感兴趣,首先想象的是你可以做(map movie-genre lst),这样你就可以获得一个在你的主助手中使用的流派列表。

在你的主助手中,你可以建立一个具有流派和数量的缺点列表。为此,您使用count的帮助(count 'c '(a b c d c c a) 0) ==> 3,您只需获取第一个类型并将列表作为第一个累计值计算,然后处理(remove 'c '(a b c d c c a) '()) ==> (a d b a)的结果。的清单。 处理完毕后,您在累加器((a . 4) (b . 6) ...)中就有了帮助(max-genre 'a 4 '((b . 6) (c . 20) (d . 10))) ; ==> c

主助手看起来像这样:

(define (aux lst acc)
  (if (null? lst) 
      (max-genre (caar acc) (cdar acc) (cdr acc))
      (aux (remove (car lst) lst '())
           (cons (cons (car lst) (count (car lst) lst 0)) acc))))

现在你可以通过一次hash table更简单地做到这一点。在阅读完所有元素后,您仍然需要max-genre / argmax

答案 1 :(得分:0)

首先,您需要确定键值数据类型。您可以使用关联列表,但哈希表是更有效的选择。

让我们从一个简短的清单开始:

(define-struct movie (title genre stars))
(define films
  (list
   (make-movie "Godfater" "Crime" '("Marlon Brando" "Al Pacino"))
   (make-movie "Rambo" "Thriller" '("Sylvester Stallone"))
   (make-movie "Silence of the Lambs" "Crime" '("Jodie Foster" "Anthony Hopkins"))))

并创建一个空哈希表

(define h (make-hash))

现在我们处理每部电影,随时更新哈希表:

> (for-each (lambda (e) (hash-update! h e add1 0)) (map movie-genre films))
> h
'#hash(("Thriller" . 1) ("Crime" . 2))

现在我们需要找到最高的数量:

> (hash-values h)
'(1 2)
> (define most (foldl (lambda (e r) (if (> e r) e r)) 0 (hash-values h)))
> most
2

所以2是我们最高的数。现在我们创建一个包含计数2的所有类型的列表:

> (hash->list h)
'(("Thriller" . 1) ("Crime" . 2))
> (foldl
   (lambda (e r)  (if (= (cdr e) most) (cons (car e) r) r))
   null
   (hash->list h))
'("Crime")

全部放在一起:

(define (count-by-genre lst)
  (define h (make-hash))
  (for-each (lambda (e) (hash-update! h e add1 0)) (map movie-genre lst))
  (define most (foldl (lambda (e r) (if (> e r) e r)) 0 (hash-values h)))
  (foldl
   (lambda (e r)  (if (= (cdr e) most) (cons (car e) r) r))
   null
   (hash->list h)))

但由于以下几个原因,这是非常低效的:

  1. 更新哈希表后,我们必须重新迭代它,创建一个列表,然后应用foldl只是为了找到最高值,而我们可以在更新哈希表时记下它
  2. 然后我们再次使用hash->list创建完整列表(foldl)和最终结果列表。
  3. 很多东西和东西。使用特定于Racket的for构造的另一种更高效的版本可能是:

    (define (count-by-genre lst)
      (define h (make-hash))
      (define most
        (for/fold ((highest 0)) ((e (in-list (map movie-genre lst))))
          (define new (add1 (hash-ref h e 0)))
          (hash-set! h e new)
          (max highest new)))
      (for/fold ((res null)) (((k v) (in-hash h)))
        (if (= v most) (cons k res) res)))