2016-11-01はじめにRubyではEnumerable#each_consを使って簡単にN-gramを作ることができます。Enumerableなオブジェクト”を読んだことをきっかけに書きました。74,779Amazon.co.jpで詳細を見るN-gramN-gramは文字列をN文字単位で区切って1要素としたものです。N-gramは全文検索を高速に行うためのインデックスとして良く使われます。Nが2のものをbi-gram(バイグラム)、Nが3のものをtri-gram(トライグラム)と呼びます。Nが4以上は応用例が少なくメジャーでないためか、私は聞いたことがありません。最初の文章をbi-gramで表現して並べると以下のとおりです。文字列の先頭からはじめて、1文字ずつずらしながら、2文字単位で1要素としていきます。Enumerable#each_consRubyではEnumerable#each_consを使って、このようなN-gramを簡単に作ることができます。Enumerable#each_consのRubyリファレンスマニュアルの解説は以下のとおりです。ブロックに渡して繰り返します。同じメソッドにEnumerable#each_sliceがありますが、”重複ありで”の部分がポイントです。このメソッドは実際に使ってみないと、なかなか用途に気づきにくいかも知れません。1.8.7や1.9以降では何もしなくても使えます。1.8.6ではenumeratorモジュールで使えるようです。文字列を入力にbi-gramを作ってみます。この例ではbi-gramの各要素を2文字の文字列で表現し、それを配列にして出力することにします。"y!"]簡単ですね。メソッドチェーンを使えば、実質一行で書くことができます。一応、処理を分解してみます。String#each_charを使って、文字列中の文字を1文字つずつ取り出すEnumeratorオブジェクトを得ます。EnumeratorオブジェクトはEnumerableの機能を提供するラッパクラスです。よってEnumerable#each_consに引数2を与えて使えば、2要素ごとに区切った配列を返すEnumeratorが得られます。'b']のような配列です。配列の要素をArray#joinで結合するよう、Enumerable#mapで処理すればbi-gramの配列になります。Enumerable#each_sliceは引数で与えた任意の要素数で区切ってくれます。引数を3にすれば、tri-gramも同じ要領で作れます。"by!"]簡単にN-gramが作れるようにStringクラスにto_ngramメソッドを追加してみるとこんな感じでしょうか。#41ではArray#*は引数に文字列を渡すとArray#joinと同じ働きをするので、配列を結合してN-gramにする部分は以下のように書けるという話題もありました。"ab"玄人感が高まりました。仮に無駄なスペースを省くと、配列に*''の3文字を足すだけで結合でき、.joinより2文字短くできます。コードゴルフでは役に立ちそうですが、この例ではjoinを使った方が無難です。&:joinを使うと良い、というコメントをTwitterでいただきました。ご指摘ごもっともです。この書き方でString.to_ngramを書き直すとすっきりしますね。endendおわりにkawasaki.rbは和気あいあいとした楽しい地域Rubyコミュニティです。#42は11月30日(水)にJR川崎駅徒歩3分のミューザ川崎で開催予定です。開催が近づくとConnpassで告知が出ます。みなさまもぜひお越しください。xmisaoプログラマ。Rubyでhttp_wire_traceオプションを使ってAPIとの通信内容を出力する2018-09-02ChromebookでLinuxを動かす。69でC101PAは完璧なLinuxノートになる。