2017-03-01 5 views
-2

異なるファイルに格納されているさまざまな文字列の数を取得したいとします。実際には2種類のカウントが必要です。文字列strの場合、Rubyでバイナリ検索ツリーを使用して文字列を取得する

1.)すべてのファイルで文字列strの出現回数の合計。 2.)文字列strを持つファイルの数。

以下は私の総数を得ることができた私のルビーコードです。 しかし、私はファイル数を得ることができません。私は単純化のためにファイルの代わりに(ファイルに似た)配列とインスタンス変数 'flag'を使用しました。

私の考えは、flag = 0の場合、最初の配列で初めて文字列が検出されたことを意味します。したがって、filecount(またはこの場合はarraycount)がインクリメントされ、flagは1に設定されます。同じ文字列が同じ配列内にある場合、flagはすでに1に設定されていて何も起こりません。 配列が終了すると、すべてのフラグ値が0に戻されます。(私はそうだと思います)

しかし、何かが期待どおりに機能していません。前もって感謝します..!

class Tree 
    attr_accessor :left 
    attr_accessor :right 
    attr_accessor :data 
    attr_accessor :count 
    attr_accessor :flag 
    attr_accessor :howmanyfiles 

    def initialize(x=nil) 
    @left = nil 
    @right = nil 
    @data = x 
    @count = 1 
    @flag = 0 
    @howmanyfiles = 1 
    end 


    def search(x) 
     if self.data == x 
     self.count = self.count + 1 
     if self.flag == 0 
      self.howmanyfiles = self.howmanyfiles + 1 
     end 
     return "#{self.data} found" #self 
     else 
     ltree = left != nil ? left.search(x) : nil 
     return ltree if ltree != nil 
     rtree = right != nil ? right.search(x) : nil 
     return rtree if rtree != nil 
     end 
    nil 
    end 


    def insert(x) 
    list = [] 

    if @data == nil 
    @data = x 
    self.flag = 1 
    elsif @left == nil 
    @left = Tree.new(x) 
    self.flag = 1 
    elsif @right == nil 
    @right = Tree.new(x) 
    self.flag = 1 
    else 
    list << @left 
    list << @right 
    loop do 
    node = list.shift 
    if node.left == nil 
     node.insert(x) 
     break 
    else 
     list << node.left 
    end 
    if node.right == nil 
     node.insert(x) 
     break 
    else 
     list << node.right 
    end 
    end 
    end 



    end 

    def traverse() 
    list = [] 
    yield @data 
    list << @left if @left != nil 
    list << @right if @right != nil 
    loop do 
    break if list.empty? 
    node = list.shift 
    yield node.data 
    list << node.left if node.left != nil 
    list << node.right if node.right != nil 
    end 
    end 






end 


    items = ["Amal","Hai", "Bob", "Bob", "Cat", "Cat", "Amal", "Dog", "Rizu", "Zol","Amal"] 

    tree = Tree.new 

    items.each {|x| 

    if tree.search(x) == nil 
     tree.insert(x) 
    end} 


    ObjectSpace.each_object(Tree) do |obj| 
     obj.flag = 0 
    end 

    items1 = ["Amal","wet", "jjj", "Cat"] 
    items1.each {|x| 

     if tree.search(x) == nil 
      tree.insert(x) 
     end} 



     ObjectSpace.each_object(Tree) do |obj| 
     obj.flag = 0 
     end 

     items2 = ["aa","Amal", "jjj"] 
     items2.each {|x| 

      if tree.search(x) == nil 
      tree.insert(x) 
      end} 

    ObjectSpace.each_object(Tree) do |obj| 
    puts obj.data.to_s + " " + obj.count.to_s + " " + obj.howmanyfiles.to_s 
    end 

    tree.traverse {|x| print "#{x} "} 
    print "\n" 

OUTPUT - ArrayCount

aa 1 1 
jjj 2 2 
wet 1 1 
Zol 1 1 
Rizu 1 1 
Dog 1 1 
Cat 3 2 
Bob 2 2 <--Bob is only present in first array but still output says 2. 
Hai 1 1 
Amal 5 3 
Amal Hai Bob Cat Dog Rizu Zol wet jjj aa 
+0

あなたが発生しているエラーは何ですか?予想される出力とは対照的に、プログラムのスタックトレースまたは出力を共有できますか? – Sinstein

+0

文字列Bobを持つ配列の数が間違っています。 ご覧のとおり、1つの配列にはBobがありますが、出力リストの数は2になります。 –

+1

ここでのインデントはちょっと混乱しています。明確にコミュニケーションの意思を伝えるのに役立つように質問するときは、コードを可能な限り整理してください。 – tadman

答えて

0

TOTAL_COUNT文字列の形式での質問は、最初の2つの段落から明らかなようだが、私は二分探索木を有利に使用することができる方法を理解することはできません。私の解決策は、希望のカウントを得るための挑戦的なアプローチです。

コード

def get_counts(filenames, target) 
    filenames.each_with_object([0, 0]) do |fname, arr| 
    n = File.read(fname).scan(/#{target}/).size 
    next if n.zero? 
    arr[0] += n 
    arr[1] += 1 
    end 
end 
filesは、ファイル名の配列です

targetは、我々が探している文字列です。

はのは、3つのテストファイルを作成することから始めましょう。

filenames = ['file1', 'file2', 'file3'] 
text  = ["Hoya, Bob. Your bro's name is Bob too. Eh?", 
       "I gotta go feed my cat", 
       "A girl named Bob?"] 

filenames.zip(text).each { |fname, str| File.write(fname, str) } 

ファイルが書き込まれたことを確認:次に

filenames.map { |fname| File.read(fname) } 
    #=> ["Hoya, Bob. Your bro's name is Bob too. Eh?", 
    # "I gotta go feed my cat", 
    # "A girl named Bob?"] 

たちは、文字列

target = 'Bob' 

を探していると仮定し

tot, files = get_counts(filenames, target) 
    #=> [3, 2] 
tot 
    #=> 3 
files 
    #=> 2 
+0

答えてくれてありがとう@Cary。しかし、私はいくつかの疑問を持っています。 私は20,000,000以上の線を持つ1000以上のファイルに存在するすべての行(文字列)に対してこの検索処理を実行する必要があります。 通常の線形検索を実行しようとしましたが、時間がかかります。だから私はバイナリ検索ツリーを使って時間を短縮するように求められました。 したがって、ルビーのスキャン方法はどのようなアルゴリズムですか?または私はこのことを行うことができる任意の効率的な方法はありますか? –

+0

あなたは大きなファイルを扱っていることを知らないので、私は[IO#read](http://ruby-doc.org/core-2.3.0/IO.html#method-read)を使って各ファイルを文字列にしました。 。大きなファイルの場合は、ファイルを1行ずつ読み込みます(例:[IO#for_each](http://ruby-doc.org/core-2.3.0/IO.html#method-c-foreach ))。私のコードはほとんど変わらないでしょう。 [String#scan](http://ruby-doc.org/core-2.3.0/String.html#method-i-scan)を各行に適用し、これらの合計をすべての行で合計します(cont 。) –

+0

...私の答えは、単語の単語や部分文字列ではなく、文字列を検索するためです(質問の仕様の一部ではないためです)。単語が必要な場合は、別のやり方で行う必要があります(たとえば、単語の境界で正規表現を使用するなど)。たとえば、「cat」という単語を検索していて、その文字列を検索しただけの場合は、「catsup」、「catch」などが数えられます...(続き) –

関連する問題