From: Tanaka Akira Date: 2009-07-29T00:29:50+09:00 Subject: [ruby-dev:38935] Re: Enumerator#peek In article , keiju@ishitsuka.com (石塚圭樹) writes: > あるグループに分けて集計したいなら, 下記のような方が Ruby ぽいかも. > > a = %w[banana banana durian orange orange orange] > a.group_by{|w| w}.each{|key, values| puts "#{key} #{values.size}"} > > MapReduce系では上記のような感じで書くことが多いと思います. group_by は残念なことにぜんぶメモリに読み込むことになるんで すよね。 ソート済みであることを前提としてシーケンシャルに処理できるメ ソッドも当然あり得て、それはそれで考えています。 [ruby-dev:38392] から始まるスレッドで、ちょっとほったらかし にしているのですが、忘れているわけではありません。 そういう、シーケンシャルに処理する操作の中で、peek はかなり 低級なところを支援する話にあたります。 狙っているところが違う感じでしょうか。 > 手前みその話ですが, fairyでは groupingした結果をinjectする処理がかなり > 多いのでは? という話になっていて, inject_by(仮名)を導入しようという話に > なっています. そうした場合, Ruby流に書けば: > > a = %w[banana banana durian orange orange orange] > a.inject_by(proc{|w| w}){|key, values| puts "#{key} #{values.size}"} > > のような感じの記述になる予定です. [ruby-dev:38392] からの提案はいろいろと変遷しているのですが、 現時点での形態の slice_by だと次のように書けます。 a = %w[banana banana durian orange orange orange] a.slice_by {|w| w }.each {|key, values| puts "#{key} #{values.size}" } まぁ、values が大きくなるとメモリの点では悲しいケースが出て くるかも知れませんが。 > また, each_consを用いて > > a = %w[banana banana durian orange orange orange] > a.push nil #-------------------------------------------(1) > e = a.to_enum > n = 0 > e.each_cons(2) do |word, peek1| > n += 1 > if word != peek1 > puts "#{word} #{n}" > word = nil > n = 0 > end > end > > の様にも書けます. (1)が味噌なんですが... (1)しなくてもちゃんと処理して > くれるeach_with_peek見たいのがあってもよいかも? 最初か最後で特別扱いが必要なのであんまりよくないと思います。 あと、コントロールブレイクを検索したところ、どうやら複数のキー を扱うことも珍しくないようです。 たとえば、咳さんの例をちょっと変えて、 word1 docid1 linenum1 word1 docid1 linenum2 word1 docid2 linenum3 word1 docid2 linenum4 word2 docid1 linenum5 word2 docid1 linenum6 word2 docid2 linenum7 word2 docid2 linenum8 というような並びを集計するには、多重ループで書きたいわけです。 たとえば、以下のような感じで。 each_word {|word| # word 単位の集計の初期化 each_docid {|docid| # docid 単位の集計の初期化 each_linenum {|linenum| ... } # docid 単位の集計の終了 } # word 単位の集計の終了 } でも、each_with_peek のようなイテレータではこういう多重ルー プは実現できません。おそらく。 ここで、上記の多重ループは再帰降下パーザとみなすこともできま す。そのように考えてトークンの取得に相当するところに Enumerator#{peek,next} を使うと、これは実現できます。 なぜ内部イテレータでなく、外部イテレータを拡張しているのか、 という理由はここにあります。 -- [田中 哲][たなか あきら][Tanaka Akira]