Scheme 编写返回字符串中单词频率的函数

Scheme 编写返回字符串中单词频率的函数,scheme,racket,Scheme,Racket,因此,对于我的代码,我需要编写一个函数,返回字符串中单词的频率。 到目前为止,我有以下代码: (define (num-occurs sym lst) (define (counter sym lst count) (cond ((null? lst) count) ((equal? (car lst) sym) (counter sym (cdr lst) (+ 1 count))) (else (counter sym (cdr lst)

因此,对于我的代码,我需要编写一个函数,返回字符串中单词的频率。 到目前为止,我有以下代码:

(define (num-occurs sym lst)
  (define (counter sym lst count)
    (cond ((null? lst) count)
          ((equal? (car lst) sym) (counter sym (cdr lst) (+ 1 count)))
          (else (counter sym (cdr lst) count))))
  (counter sym lst 0))

(define (remove-all elem lst)
    (if (null? lst)
        '()
        (if (equal? elem (car lst))   
            (remove-all elem (cdr lst))
            (cons (car lst) (remove-all elem (cdr lst))))))

(define (word-frequencies str)
  (let ((lst (string->list str)))
  (if (null? lst)
      '()
          (append (list (cons (car lst) (num-occurs (car lst) lst)))
                  (word-frequencies (remove-all (car lst) (cdr lst)))))))
当我给它一个输入,比如:(单词频率“hi there person hi”)

我得到这个错误。 字符串->列表:违反合同 预期:字符串? 给定:(#\i#\space#\t#\e#\r#\e#\space#\p#\e#\r#\s#\o#\n#\space#\i)

我们会感激你的帮助,为什么它会这样做? 我希望我的最终输出看起来像


((hi.2)(there.1)(person.1))

错误的原因是
string->list
函数返回了一个字符列表。因此,如果您尝试这样做:

(string->list "hi there person hi")
你最终会得到
”(\#h\#i\#space\#t\#h\#e…
而不是
”(你好,有人你好)

最简单的方法是通过扫描字符列表并检测当前字符(
car
)何时为
#\space
(空白)来从字符串组成一个符号列表,并基于此构建每个单词字符串。这可能不是最有效的方法,但它确实起到了作用

(define (string-to-lat str)
  (let ([char-list (string->list str)])
    (let build-list ([s char-list] [l '()] [w ""])
      (cond ((null? s) l)
            ((null? (cdr s))
             (append l (list (string->symbol (string-append w (string (car s)))))))
            (else
             (if (char=? (car s) #\space)
                 (build-list (cdr s) (append l (list (string->symbol w))) "")
                 (build-list (cdr s) l (string-append w (string (car s))))))))))
(指向lat“hi there person hi”的字符串)
将返回
”(hi there person hi)

以下是步骤:

  • 使用
    string->list
    将字符串转换为字符列表
  • 构建递归函数
    构建列表
    ,将初始作用域变量绑定到初始值
  • 关键部分在于最后一个
    if
    表达式,如下所示
    • 如果找到空格,则使用不带空格的字符列表调用
      build list
      ,并通过向其追加
      w
      并将
      w
      重置为空字符串来更新
      l
    • 否则,通过在字符串
      w
      后追加
      (字符串(汽车))
      来正常重复
  • w
    是一个单词累加器,每当在
    s
    char列表中发现空格时,它可以帮助构建每个单词并将其转换为符号,并将其放入最终列表中


    这样,计算结果列表中每个符号的出现次数应该很简单。

    我学到的一件事是,您应该在解释器中测试您的假设:

    > (string->list "hi")
    '(#\h #\i)
    
    string->list
    生成字符列表,而不是字符串列表。
    当您稍后尝试在该字符列表上递归时,此功能将崩溃。
    (即使
    string->list
    生成了字符串列表,递归也会中断,因为函数需要的是字符串,而不是列表。)

    Racket有许多有用的库函数,您正在寻找的函数确实存在

    string split
    将字符串(默认为空白)拆分为字符串列表

    > (string-split "hi there hi")
    '("hi" "there" "hi")
    
    还有一个
    groupby
    ,它将一个列表分组为一个列表列表。
    (在优秀手册中查找这些功能。)
    groupby
    需要一些分组依据。让我们使用字符串本身

    > (define id (lambda (x) x))
    > (group-by id (string-split "hi there hi"))
    '(("hi" "hi") ("there"))
    
    这看起来很有用。
    我们还可以使用一个函数来构建单词和频率对:

    > (define (frequency-pair strings) (cons (car strings) (length strings)))
    > (frequency-pair '("hi" "hi"))
    '("hi" . 2)
    > (map frequency-pair (group-by id (string-split "hi there hi")))
    '(("hi" . 2) ("there" . 1))
    
    综合起来:

    (define (word-frequencies str)
      (define (id x) x) ; Group strings by their own value
      (define (frequency-pair strings) (cons (car strings) (length strings)))
      (map frequency-pair (group-by id (string-split str))))
    
    > (word-frequencies " hi hello hi there over there")
    '(("hi" . 2) ("hello" . 1) ("there" . 2) ("over" . 1))
    

    请注意,
    string->list
    返回的是字符列表,而不是符号列表。因此
    (string->list“hi”)
    返回
    (#\h#\i)
    。您知道如何将字符串直接转换为列表吗?所以它就变成了“(hi-there-person-hi)。您可以拆分字符串并在结果字符串列表上映射
    字符串->符号,即
    (映射字符串->符号(字符串拆分“hi there person hi”)
    @M.Maric请参见我的答案。这应该很简单。