2017-11-07 6 views
2

私のコードでは、文字列中の単語の頻度を返す関数を書く必要があります。 (単語頻度「こんにちは人こんにちは」)私はこのエラーを取得する文字列内の単語の頻度を返す関数を書く

:私はそれをのような入力を与えるとき

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

: は、これまでのところ私は、次のコードを持っています。 string-> list:契約違反 expected:文字列? が与えられました:(#\ i#\スペース#\ t#\ e#\ r#\ e#\スペース#\ p#\ e#\ r#\ s#\ o#

なぜこれがこれを行うのでしょうか? 私の最終的な出力は、次のようになります。

((HI。2)(そこに。1)(人。1))

+0

は、文字のリストを返しますlist'はstring-> 'があることに注意してください
は、我々はまた、単語や周波数のペアを構築する機能を利用することができます記号ではありません。だから '(string-> list" hi ")'は '(#\ h#\ i)'を返します。 – PieOhPah

+0

文字列からリストに直接どのようにすることができるか知っていますか?だからそれはちょうど '(hi there person hi)になります。 –

+0

文字列を分割し、 'string-> symbol'を文字列の結果リストにマップすることができます。 '(マップ文字列 - >シンボル(文字列分割" hi there person hi "))'。 – assefamaru

答えて

1

ことの一つは、あなたが通訳であなたの仮定をテストするべきであるということです。

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

string->listは、文字のリストではなく、文字列のリストを生成します。
この文字リストを後で再帰的に処理しようとすると、これが中断します。
string->listは、文字列のリストを作成しなかった場合でも、あなたの関数は、文字列ではなく、リストを期待するので、再帰が壊れる。)

ラケットは、多くの有用なライブラリ関数を持っており、あなたがを探している1が行いますが存在します。

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)) 
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. キー部分は
    • は、「スペースが見つかった場合、スペースなしで文字のリストでbuild-listを呼び出し、このように書き、最後if表現であり、そしてそれにwを追加することによってlを更新し、それ以外の場合は
    • 。空の文字列にwをリセットし、文字列w(string (car s))を追加することによって、通常は再発。

wは、各単語を構築して記号に変換し、s charリストに空白が見つかるたびに最終的なリストに入れるのに役立つ単語アキュムレータです。

このように、結果のリスト内の各シンボルの出現を数えるのは簡単です。私が学んだ

関連する問題