SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

C++開発者のためのRubyガイド

同じ動作をするプログラムでC++とRubyの実装を比較する

ダウンロード サンプルソース (2.4 KB)

Rubyでの実装

 以下がRubyでの実装になります。

リスト2 Rubyでの実装
require 'rexml/document'
require 'set'

class WordCount

  # read-only attributes
  attr_reader :word, :total_count

  def initialize(word)
  @word = word
  @total_count = 0
  end

  # Use a mixin of Comparable module to get comparisons for free 
  # we must define <=>
  include Comparable

  def <=>(other)
    return @total_count <=> other.total_count  
  end

  def add(filename)
    @total_count += 1
  end

  def file_occurrences
    return []
  end
  
end

class WordAndFileCount < WordCount

  # read-only attributes
  attr_reader :file_hash

  def initialize(word)
  super(word)
  @file_hash = Hash.new
  end

  def add(filename)
  @total_count += 1
  v = @file_hash[filename]
  @file_hash[filename] = (v == nil) ? 1 : v + 1
  end

  def file_occurrences
    return @file_hash.sort { |x,y| ?(x[1]<=>y[1]) }
  end
  
end

class WordCounter

  def initialize(directory_name)
    @directory_name = directory_name
    @word_count = Hash.new
  end


  def count_words
    pwd = Dir.pwd
    Dir.chdir @directory_name
    Dir.foreach(".") { |filename|
       count_words_in_file filename 
    }
    Dir.chdir pwd
  end

  def dump_results
    root = REXML::Element.new "counts"
    @word_count.values.sort.reverse.each { |wc|
      e = root.add_element "word", {"occurences"=>"#{wc.total_count}"}
      e.add_text wc.word
      wc.file_occurrences.each { |pair| 
        f = e.add_element "file", {"occurences"=>"#{pair[1]}"}
        f.add_text pair[0]
      }
    }

    doc = REXML::Document.new
    doc << REXML::XMLDecl.new
    doc.add_element root
    doc.write $stdout
  end

  private

  def count_words_in_file(filename) 
    return if File.directory? filename

    File.open(filename) { |file|
      file.each_line { |line|
        words = line.split(/[^a-zA-Z]/) 
        words.each { |w| 
          next if w.size == 0
          @word_count[w] = $count_gen.call(w) if @word_count[w] == nil
          @word_count[w].add filename
        }
      }
    }
  end

end

if ARGV.include?("--no-file-info") then
ARGV.delete("--no-file-info")
$count_gen = lambda { |word| WordCount.new word }
else
$count_gen = lambda { |word| WordAndFileCount.new word }
end

counter = WordCounter.new ARGV[0]
counter.count_words
counter.dump_results

クラスと変数の基本

 両バージョンとも、次の3つのクラスを定義します。

  1. 全ファイルでのワードの出現総数を表すクラス(word_count/WordCount)
  2. 上のクラスから派生し、ファイルごとの各ワードの出現を保持する拡張クラス(word_and_file_count/WordAndFileCount)
  3. ファイルの読み込みとパース、ワードカウントの作成と更新、およびXMLファイルの出力を行うカウンタクラス(word_counter/WordCounter)

 1つ目のクラスは、リスト1では22行目、リスト2では4行目で定義されています。両実装とも、文字列wordtotal_count変数を保持しています。Rubyでは、インスタンス変数の先頭には「@」が付くため、リスト2には、@word@total_countがあります。ローカル変数にはプレフィックスは付きません。一方、グローバル変数には「$」というプレフィックスが付きます。

 C++コードでは、structを使用してこのクラスを宣言します。したがって、word変数とtotal_count変数は既定ではパブリックです。しかし、Rubyでは、オブジェクトの外部からはインスタンス変数にアクセスできず、すべての変数がプライベートになっています。アクセスコントロールについては後でもっと詳しく解説しますが、ここでは、必要なアクセッサメソッドを追加することに焦点をあてて説明します。リスト1の7行目のステートメントを見るとわかりますが、このようなアクセッサメソッドは簡単に追加できます。attr_readerの後に変数をリストすれば、必要なgetアクセッサメソッドを自動的に生成できます。

 また、このクラスではどちらの実装でも、ワード文字列を取得するコンストラクタと、カウンタをインクリメントするaddメソッド、さらにファイルごとの情報を保持するデータ構造を返すfile_occurrencesメソッドを定義します。リスト2の9行目で示すように、Rubyのクラスコンストラクタには、initializeという名前が付いています。

 Rubyコード中のinclude Comparableの部分を除けば、この基本クラスの実装はどちらの言語でもかなりわかりやすいものになっています。

次のページ
継承と多態性

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Michael Voss(Michael Voss)

Intel社のSenior Staff Software Engineer。2001年にPurdue大学からElectrical Engineering博士号を授与された。現在、IntelのThreading LabとToronto大学の非常勤講師を掛け持つ。平行プログラミングとコンパイラの最適化に...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1438 2007/06/28 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー