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

时间:2017-11-07 00:44:30

标签: 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) 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”)

我收到此错误。 string-&gt; list:合同违规   预期:字符串?   给出:(#\ i#\ space#\ t#\ e#\ r#\ e#\ space#\ p#\ e#\ r \ n#\ s#\ o#\ n#\ space#\ i)< / p>

帮助将被理解为什么它这样做? 我希望我的最终输出看起来像。

((hi.2)(那里)(人.1))

2 个答案:

答案 0 :(得分:1)

我学到的一件事是你应该在翻译中测试你的假设:

> (string->list "hi")
'(#\h #\i)

string->list生成一个字符列表,而不是字符串列表 当您稍后尝试递归此字符列表时,这会中断 (即使string->list确实产生了一个字符串列表,递归也会破坏,因为你的函数需要一个字符串,而不是一个列表。)

Racket有许多有用的库函数,而你正在寻找的 存在。

string-split将字符串(默认情况下为空格)拆分为字符串列表。

> (string-split "hi there hi")
'("hi" "there" "hi")

还有group-by,它将列表分组到列表中 (在优秀的手册中查找这些功能。)
group-by需要分组。让我们自己使用字符串。

> (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))

答案 1 :(得分:0)

错误的原因是因为string->list函数返回了一个字符列表。所以如果你尝试做这样的事情:

(string->list "hi there person hi")

您最终会使用'(\#h \#i \#space \#t \#h \#e ...)而不是'(hi there person hi)

最简单的方法是通过扫描字符列表来组成字符串中的符号列表,并检测当前字符(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))))))))))

(string-to-lat "hi there person hi")将返回'(hi there person hi)

以下是步骤:

  1. 将字符串转换为string->list的字符列表。
  2. 构建递归函数build-list,将初始范围变量绑定到初始值。
  3. 关键部分在于最后一个if表达式,就像这样
    • “如果找到空格,请使用不含空格的字符列表调用build-list,并通过向其添加l更新w,然后重置w一个空字符串。
    • 否则,通过将(string (car s))附加到字符串w来正常重复。
  4. w是一个单词累加器,它可以帮助构建每个单词并将其转换为符号,并在s字符列表中找到空格时将其放入最终列表中。

    通过这种方式,可以直接计算结果列表中每个符号的出现次数。