使用`map`进行球拍计数

时间:2017-11-27 16:41:29

标签: scheme racket map-function

  

编写一个Racket函数count-occurrences,它使用两个符号列表并生成一个列表   测量第一个列表中的项目在第二个列表中出现的次数的自然数。例如:

(count-occurrences (list 'a 'b 'a 'q) (list 'r 'a 'b 'e 'b 'g))
     

=> (清单1 2 1 0)

我一直在努力解决这个问题 - 如何使用map来解决这个问题,因为对于这个问题我们指定的不能使用递归。

我最初的想法是做以下事情:

(define (count-occurrences los1 los2) 
  (map
   (length (filter (lambda (x) (symbol=? x (first los1))) los2))
   los1))

但是在这里使用length只能得到数字' a而不是进入递归。对于抽象函数,内部函数只能有一个参数,所以我完全迷失了。

3 个答案:

答案 0 :(得分:3)

如果... x ...开放公式,即引用未绑定变量x的表达式,则将其包装在lambda中} form使它成为x中的一个函数,如下所示:

(lambda (x) ... x ... )

其中x被该lambda表单绑定;这个所谓的lambda函数的参数,也就是说,lambda形式引入的匿名函数。

因此,解决问题的方法非常简单:认识到

    (length
        (filter (lambda (x)               
                     (symbol=? x (first los1)))
                los2))

实际应该是

    (length
        (filter (lambda (x)               
                     (symbol=? x y))
                los2))

其中y依次引用每个los1元素,不是只是第一个;并且它是y中的开放式公式 - 也就是说,y未绑定,免费。因此,我们必须捕获它,并使其绑定,通过...是的,将此表达式括在lambda形式中,从而使其成为 y中的函数!像这样:

  (lambda (y)
    (length
        (filter (lambda (x)               
                     (symbol=? x y))
                los2)))

是通过los1映射的内容。

通过这种简单的调整,您的代码将成为正确的工作函数定义。

答案 1 :(得分:1)

这是否符合您的要求和限制?

(define (count-occurrences lst1 lst2)
  (map (lambda (e1)
         (count (lambda (e2) (eq? e1 e2))
                lst2))
       lst1))

答案 2 :(得分:0)

跟踪密钥和值的好方法是使用哈希表。虽然可以使用count-occurrences编写map并传递lambda,但显式可能会让您更容易看到正在发生的事情。

;;; list list -> list
;;; 
(define (count-occurrences keys values)

  ;; Create data structure
  (define ht (make-hash))

  ;; Initialize data structure with keys
  ;; Set the value of each key to zero
  ;; Since we have not started counting
  (for ([k keys])
    (hash-set! ht k 0))

  ;; Iterate over values and
  ;; Increment hash table if
  ;; When value is a key
  (for ([v values])
    (if (hash-has-key? ht v)
      (hash-set! ht v (+ (hash-ref ht v) 1))
      null))

  ;; Iterate over keys and
  ;; Create list of values 
  (for/list ([k keys])
    (hash-ref ht k)))

由于禁止递归,显式循环可以使得比隐式循环更易于维护/读取代码。此外,for的变化值得了解。散列表的优点是重复键读取相同的值,并且不需要两次跟踪相同的键。

使用for而不是map的一个工程优势是,更容易推断运行时间。此代码的运行时间为2m + n,其中mkeysnvalues。使用map的解决方案通常为m * n。这没有什么本质上的错误。但值得认识的是。