ハッシュ(単語数を数える)の解説 | Ruby

このQ&Aのポイント
  • Rubyの例題「ハッシュ(単語数を数える)」の解説について質問があります。
  • 疑問1: ハッシュcountのキーと値の内容が決まる理由を教えてください。
  • 疑問2: count[word] += 1 の内容について教えてください。
回答を見る
  • ベストアンサー

ハッシュ(単語数を数える) たのしいRuby

たのしいRuby P252に掲載されていた、例題 「ハッシュ(単語数を数える)」の解説を読んでも 意味が分からなかったので教えてください。 ■例題word_count.rb 1:# 単語数のカウント 2: 3: count = Hash.new(0) 4: 5:## 単語の集計 6:while line = gets 7: words = line.split 8: words.each{|word| 9: count[word] += 1 10: } 11:end 12: 13:## 結果の出力 14:count.sort{|a,b| 15: a[1] <=> b[1] 16:}.each{|key, value| 17: print "#{key}: #{value}\n" 18} ■疑問1. 解説には、 # 3行目で出現回数を記録するハッシュcountを作ります。 # countは、キーが単語、値がその単語が出現した回数を表します。 と書かれているのですが、「キーが単語、値がその単語が出現した回数を表します」 の内容が理解できません。newしただけなのに、どうして、 キーと値の内容が決まるのでしょうか? ■疑問2. 解説には、 # 8行目からの繰り返しでは、それぞれの単語をキーにして、countから出現回数を取り出し、 # +1します。 と書かれているのですが、「count[word] += 1」 の内容が理解できません。 作成したハッシュcountと、getsメソッドで読み込み単語単位に分割した配列wordsとが、 どこで関連付けされているのかが、分かりません。 ■疑問3. 解説には、 # ruby word_count.rb README という形で、Rubyに同梱されているREADMEファイルの単語数を調べた 実行結果が掲載されているのですが、 そのときの具体的な処理の流れが分かりません。 「ruby word_count.rb README」と書くだけで、 処理の流れが、getsの所まできたとき、 自動的に指定ファイル名を判断し、 読み込みを始めるということなのでしょうか。

  • re999
  • お礼率61% (476/777)
  • Ruby
  • 回答数1
  • ありがとう数15

質問者が選んだベストアンサー

  • ベストアンサー
  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

>と書かれているのですが、「キーが単語、値がその単語が出現した回数を表します」 >の内容が理解できません。newしただけなのに、どうして、 >キーと値の内容が決まるのでしょうか? 別に決まってはいません。 その後のコードで count の key と value をそのように解釈して利用しているということです。 >作成したハッシュcountと、getsメソッドで読み込み単語単位に分割した配列wordsとが、 >どこで関連付けされているのかが、分かりません。 配列 words を一単語ずつ each メソッドで処理することで関連づけています。 Hash.new(0) でデフォルト値が 0 であることに注意しましょう。 >「ruby word_count.rb README」と書くだけで、 > 処理の流れが、getsの所まできたとき、 > 自動的に指定ファイル名を判断し、 > 読み込みを始めるということなのでしょうか。 gets とは ARGF.gets と同じです。

re999
質問者

補足

ご回答ありがとうございました。

関連するQ&A

  • Rubyについて質問です

    Rubyについて質問です class Document #省略 def each_word word_array = words index = 0 while index < words.size yield(word_array[index]) index += 1 end end end d = Document.new('Truth', 'Gump', 'Life is like a box of...') d.each_word { |word| puts word } このような例題があるのですが、 このまま実行しても引数エラーがでてしまいます。 「省略」のところをどのように追加すれば実行できるようになりますか? 参考書:ELOQUENT RUBYの中の例題です ちなみに実行結果は以下の通りです Life is like a box of ... どうかよろしくお願いいたします

  • Rubyでnet::httpを用いてPOSTする

    今晩わ。 RubyでNet::HTTPをもちいてPOST送信する際の処理について 質問です。 Net::HTTPクラスのインスタンスメソッドのpostメソッドを用いて送信する場合 送信内容を # version 1.2 (Ruby 1.8.x or later) response = http.post('/cgi-bin/search.rb', 'query=subject&target=ruby') 上記のように、引数に渡していると思います。 このとき、値の中にパラメータのデリミタと同じ&を入れたい場合どうしたらいいのでしょうか? 例えば query=subject&target=ruby&PHP のような感じでvalueとして&を渡す場合です。 Net**HTTP::Postクラスのrequestメソッドを用いてハッシュとして渡した時は問題なかったのですが、上記のpostメソッドの時がPOSTされた値を取得するときにキチンと取得できませんでした。これはなにか対処方法があるのでしょうか? ご教授ください。 おねがいします。

    • ベストアンサー
    • Ruby
  • 単語の出現回数を数え、出現回数順に表示するには?

    標準入力または入力ファイルから単語の出現回数を調べるプログラムの一部です。ENTRY *add_entry(ENTRY *new)関数で以前に出てきた単語か(正確には以前に同一内容の行があったかを)判断し、既出ならばvoid do_one(FILE *fp)関数内部でp->count++として出現回数に加算しています。void do_one(FILE *fp)関数の最後の方のprintfで単語とその出現回数を表示します。これだとappleという単語が2回出てくれば、 apple:1 apple:2 と表示されます。この場合は apple:2 だけ表示させ、さらに、出現回数の多い順に単語を並べて表示させたいんです。どういう風にすればいいでしょうか? typedef struct entry_t { char *str; struct entry_t *next; int count; /* 単語の出現回数 */ } ENTRY; int main(int argc, char **argv) { FILE *fp; char *s; init_hash(); --argc; ++argv; if (argc == 0) do_one(stdin); else { while (argc--) { if ((fp = fopen(*argv, "r")) == NULL) cant(*argv); /* no return */ do_one(fp); fclose(fp); argv++; } } free_all_entries(); return (0); } void do_one(FILE *fp) { ENTRY *p; char buf[MAX_SIZE]; int i; while (fgets(buf, MAX_SIZE, fp) != NULL) { if ((p = malloc(sizeof(ENTRY))) == NULL) error("can't alloc memory"); /* no return */ if ((p->str = strdup(buf)) == NULL) error("can't alloc memory"); /* no return */ if (add_entry(p) != p) { p->count++; /* 登録済みなので単語の出現回数を1増やす */ free(p->str); /* すでに登録されているので開放 */ free(p); } else /* 新しく単語を登録する場合 */ p->count =1; /* 単語の出現回数を1にする */ printf("%s : %d\n", p->str, p->count); } } void init_hash(void) { int i; for (i = 0; i < HASHSIZE; i++) table[i] = NULL; } ENTRY *add_entry(ENTRY *new) { ENTRY *p; int h; h = hash(new->str); /* 追加する単語のハッシュ値を求める */ for (p = table[h]; p != NULL; p = p->next) if (strcmp(p->str, new->str) == 0) { /* 追加済みの単語ならば */ return (p); /* そのデータのポインタを返す */ } new->next = table[h]; table[h] = new; /* 単語を追加する */ return (new); }

  • rubyの日本語名関数

    rubyの環境を変えたところ日本語の関数名が使えなくなりました。 解決策があればお願いします。 [環境] OS:Windows VISTA ruby:1.8.7-p330-i386-mswin32 (外付けHDDに展開して利用) 実行方法:cmd.exe /k "ruby.exeのパス" "rbファイルのパス" で実行 [以前の環境] OS:WINDOWS XP ruby:ActiveScriptRuby(1.8.7-p330) (Cドライブにインストール) [ソース(外部rubyファイル元.rb)] # EUC-JP :-Ke # SHIFT-JIS :-Ks # UTF-8N :-Ku # SHIFT-JISコード設定にしました #! ruby -Ks def 元関数() print "元関数だよ!\n" end require '外部rubyファイル先' print "外部ファイルの関数を実行\n" 先関数() print "内部ファイルの関数を実行\n" 元関数() print "Enterキーを押してください\n>" a = gets.to_i [ソース(外部rubyファイル先)] def 先関数() print "先関数だよ!\n" end

    • ベストアンサー
    • Ruby
  • 2つの配列/キーが一致する際、要素数の出現回数を求

    2つの配列があり、かつキーが一致する際、要素数の出現回数を求めたいのですが、 どうすれば良いでしょうか? 具体的には、下記「a、b」より「c、d」を導き出したいです ■元データ( a、b キーは対応) Array a (   [0] => 1   [1] => 2   [2] => 2   [3] => 1   [4] => 3   [5] => 1   [6] => 2   [7] => 2   [8] => 3   [9] => 1 ) Array b (   [0] => 0   [1] => 1   [2] => 0   [3] => 1   [4] => 1   [5] => 1   [6] => 1   [7] => 0   [8] => 2   [9] => 1 ) ■欲しい結果 Array c … 「Array b」が1の時の、「Array a」の値の出現回数(キーは「Array a」の値) (   [1] => 3   [2] => 2   [3] => 1 ) Array d … 「Array b」が1以外(0または2)の時の、「Array a」の値の出現回数(キーは「Array a」の値) (   [2] => 2   [1] => 1   [3] => 1 ) ■備考 「Array b」が1の時の「Array a」   [1] => 2   [3] => 1   [4] => 3   [5] => 1   [6] => 2   [9] => 1 ・1が3回 ・2が2回 ・3が1回 「Array b」が1以外の時の「Array a」   [0] => 1   [2] => 2   [7] => 2   [8] => 3 ・2が2回 ・1が1回 ・3が1回

    • ベストアンサー
    • PHP
  • カウント配列

    while文で単語を読み込んでtango[i](単語を格納している)に同じ単語があれば、配列hindo[i](単語の出現回数を格納)に1を加える。tango[i]に同じ単語がなければtango[i]に単語を追加。aはtango[i]の最後の値、keyは読み込み単語とし、単語の出現頻度を出したいのですが、うまくいきません。ソースとしては以下のものを考えました。 for(i = 0; i <= a ;i = i + 1){ if(key == tango[i]){ hindo[i] = hindo[i] + 1; break; } if(key != tango[a]){ tango[a] = key; a = a + 1; } } どうすればうまくいきますか? たびたびすいませんが、初心者なのでよろしくお願いします。

  • RubyによるCSVファイルの該当行の取り出し

    お世話になります、 Rubyプログラムにて以下のようにCSVファイルをコピー&ペーストしておりますが、 出力結果の1-4行目までの数値は必要ないため、5行目より処理をしたいのです。 良い方法があればご教示いただけないでしょうか。 ・RubyProgram <snip> p1 = ARGV[0] # p1:出力ログ対象CSV file_csv = File.open(p1,"r") while csv_word = file_csv.gets do chk_value_log.print csv_word p csv_word end file_csv.close chk_value_log.close <snip> ・出力結果 $ ruby -v aaaaa.rb bbbb.csv ruby 1.8.4 (2005-12-24) [i386-cygwin] "# name, id, name, IP address,,,,,,,,,,,,,,,,,,,,\r\n" "# name, id, name, IP address,,,,,,,,,,,,,,,,,,,,\r\n" "# name, id, name, IP address,,,,,,,,,,,,,,,,,,,,\r\n" "# name, id, name, IP address,,,,,,,,,,,,,,,,,,,,\r\n" "1,3,1101,0,32,19,1152,1,4,0,0,0,0,0,0,0,0,1152,1101,51,0,0,0,0\r\n" "1,4,254,0,7,3,264,1,3,0,0,0,0,0,0,0,0,264,254,10,0,0,0,0\r\n" "1,1,-1,0,25,66,-1,0,0,0,0,0,0,0,0,0,0,0,0,-1,70,2945,8153\r\n"

  • どこが間違いか分かりません。(Ruby)

    Rubyを使ったプログラムが巧く行かないのですが、どこでエラーが出ているのか分かりません。どなたか何が原因でエラーが起こったのか教えて頂けないでしょうか。 以下ソースコードです。 class SolitaireCipher $deck = (1..52).to_a+['A','B'] def solitaire(count) key_stream = [] until key_stream.size == count a = $deck.index("A") $deck.delete("A") if a == 53 a = 0 else a += 1 end $deck.insert(a,"A") b = $deck.index("B") $deck.delete("B") if b == 52 b = 1 elsif b == 53 b = 2 else b = b+2 end $deck.insert(b,"B") a1 = $deck[0..b-1] a2 = $deck[b..a] a3 = $deck[a+1..53] $deck = a3+a2+a1 if $deck[53] == 'A' t1 = 27 elsif $deck[53] == 'B' t1 = 27 else t1 = $deck[53] end a4 = $deck[0..t1-1] $deck = ($deck-a4).insert(52,a4).flatten! i = $deck[0].to_i key = $deck[i] key_stream << key end key_stream_s = key_stream.join n = 5 while n < key_stream_s.size key_stream_s[n,0] = " " n += 6 end key_stream = key_stream_s.split(" ") end end s = SolitaireCipher.new p s.solitaire(20) このプログラムを実行したときに、どういう訳かuntil文の中で毎回$deckの値が初期化されるようです。 そのため結果が以下のようになります。 ["44444", "44444", "44444", "44444"] 初心者プログラマーなので何か初歩的な間違いをしているのかもしれません。 どなたかエラーの原因を教えて頂けないでしょうか。 読みにくいプログラムではありますがよろしくおねがいします。

  • ハッシュを使った集計結果の出力について

    ハッシュを使った集計結果の出力について testフォルダに以下のファイルがあるとします。  aaa_1、aaa_2、bbb_1、bbb_2、ccc_1、・・・ 各ファイルには○△×がついた行があり、 「aaa」のファイル(aaa_1とaaa_2)の○△×の数、「bbb」のファイルの○△×の数、を集計したいと思っています。 出力イメージは以下です。  ファイル名の一部,○の数,△の数,×の数  aaa,13,59,37 ファイル名の一部をキーとして、 ○△×の回数を値にしたハッシュで集計しようとしましたが、 以下のようになってしまいました。 ,0,0,0 ,0,0,0,0,0,0 aaa,13,59,0 aaa,13,59,0,13,59,37 bbb,20,10,0 bbb,20,10,0,20,10,30 ハッシュが十分に分かっていないので、おかしなことをしてるのだと思うのですが。。 ご教授くださいますよう、お願いします。 opendir(DIR, $dir); while ($file = readdir(DIR)){  $maru =0;  $san =0;  $batu =0;  $file =~/(.*)_(.*)/;  $name = $1;  open(IN, "$dir/$file");   while ( $line = <FIN1> )   {    chomp( $line );    if($line =~/○/){      $maru++;    }elsif($line =~/△/){      $san++;    }elsif($line =~/×/){      $batu++;    }  } push(@{$test{$name}} , $maru,$san,$batu); @gyou = ( $name , join ("," , @{$test{$name}})) ; print OUT join (",", @gyou). "\n"; } close (IN); close (OUT);

    • ベストアンサー
    • Perl
  • 教えてください。

    このソースの中で、間違えているところはどこですか? 誰か助けてください。 /* 英単語辞書の登録と表示 */ #include <stdio.h> #define NUMBER 50 /*登録数*/ /*--- 単語帳の構造体 ---*/ struct words { char name[20]; char wayaku[50]; }; /*--- 単語と和訳の登録 ---*/ struct words touroku_word(struct words tangochou[], char ) { int count = 0; char word[20],wa[50]; while(1) { printf("英単語を登録してください。:"); scanf("%s", word); strcpy(tangochou[],*s); count++; putchar('\n'); printf("和訳を入力してください。:"); scanf("%s", wa); strcpy(tangochou[],*s); putchar('\n'); if (i < NUMBER){ return (0); } if (cont == 0){ break; } } } /*--- 登録された単語を表示する ---*/ void print_word(struct words tangochou[],int count) { int i = 0; puts("登録されている単語を表示します。\n"); for (i ; i < count; i++) { printf("[単語]:%d\n",tangochou[i].name); printf("[和訳]:%d\n",tangochou[i].wayaku); } } int main(void) { struct words tangochou[2]; int menu; while(1){ do { printf("メニュー番号を入力してください。:"); scanf("%d", &menu); if (menu > 0){ break; } }while(menu != 0); switch (menu){ case 1 : touroku_word(tangochou[]); break; case 2 : print_word(tangochou[]); break; case 3 :puts("終了します。\n"); return (0); default :puts("メニュー番号が間違っています。"); break; } } return (0); }

専門家に質問してみよう