【问题标题】:writing a function that returns the frequency of a word in a string编写一个返回字符串中单词频率的函数
【发布时间】:2017-11-07 00:44:29
【问题描述】:

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

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

当我给它一个输入时:(word-frequencies "hi there person hi")

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

帮助将不胜感激它为什么这样做? 我希望我的最终输出看起来像。

((嗨。2)(那里。1)(人。1))

【问题讨论】:

  • 请注意string->list 返回的是字符列表而不是符号。所以(string->list "hi") 返回'(#\h #\i)
  • 你知道我怎么能直接从一个字符串变成一个列表吗?所以它就变成了 '(hi there person hi)。
  • 您可以拆分字符串并将string->symbol 映射到字符串的结果列表中,即。 (map string->symbol (string-split "hi there person hi")).
  • @M.Maric 看到我的回答。它应该是直截了当的。

标签: scheme racket


【解决方案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))

【讨论】:

    【解决方案2】:

    错误的原因是因为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 并使用不带空格的字符列表,并通过将w 附加到它来更新l,并将w 重置为空字符串。
      • 否则,通过将(string (car s)) 附加到字符串w 来正常重复。

    w 是一个单词累加器,每当在 s 字符列表中找到空格时,它都会帮助构建每个单词并将其转换为符号并将其放入最终列表中。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-14
      • 2022-11-15
      • 1970-01-01
      相关资源
      最近更新 更多