1

I'm learning Ruby, and I'm having a problem while making a program.

I have a class "LineAnalyzer" that has 4 parameters (2 provided and 2 calculated). Both calculated params are: @high_wf_count (integer) and @high_wf_words (array). Then, I have this one:

class Solution < LineAnalyzer
    attr_reader :analyzers, 
                :highest_count_across_lines, 
                :highest_count_words_across_lines

    def initialize
        @analyzers = [] 
    end

    def analyze_file
        File.foreach('test.txt') do |line|
            @analyzers << LineAnalyzer.new(line.chomp,@analyzers.length+1)
        end 
    end

    def calculate_line_with_highest_frequency
        @highest_count_words_across_lines = []
        @highest_count_across_lines = @analyzers.max_by do 
            |a| a.instance_variable_get(:@highest_wf_count)
        end .instance_variable_get(:@highest_wf_count)

        @highest_count_words_across_lines << @analyzers.each do
            |a| a.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
        end .instance_variable_get(:@highest_wf_words)
    end    
end

The problem is that I cannot append the array @highest_wf_count to @highest_count_words_across_lines in the way I've done (it returns nil). But, I've previously taken the integer @highest_wf_count in the same way perfectly.

Can anyone tell me where's the problem?

Thanks in advance!

0

3 Answers 3

2

It seems that your problem is in this bit of code:

@highest_count_words_across_lines << @analyzers.each do
    |a| a.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
end .instance_variable_get(:@highest_wf_words)

Preferably formatted as:

@highest_count_words_across_lines << @analyzers.each do |analyzer|
  analyzer.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
end.instance_variable_get(:@highest_wf_words)

The problem here is that you are calling .instance_variable_get(:@highest_wf_words) on the result of the :each method.

A few lines above, you are doing something similar, where you call .instance_variable_get(:@highest_wf_count) on the result of the :max_by method, and it is working.

The difference between :max_by and :each is that :max_by returns a single analyzer, whereas :each returns the array of @analyzers over which it is iterating.

When you call :instance_variable_get(:@highest_wf_words) on that array, it's returning nil because an array will not have an instance variable named :@highest_wf_words

That is where your problem exists.

Sidenote:

It is generally not good practice to ever use :instance_variable_get. I would recommend adding to your analyzer class attr_reader :highest_wf_words, :highest_wf_count

Then, instead of calling analyzer.instance_variable_get(:@highest_wf_words), you can just call analyzer.highest_wf_words

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much!! I didn't notice the difference between those functions. And, is there any way of taking all the values :highest_wf_word in :analyzer so that its :highest_wf_count is maximum in a single line? Or any function that fits better for this need. Thanks again!
You might want to look into the :select method on arrays: ruby-doc.org/core-2.3.1/Enumerable.html#method-i-select that will allow you to filter @analyzers by only the ones with the highest_count_across_lines. If you are using :select, it also returns an array, and you'll want to use += instead of <<, because you'll want to add the arrays together, rather than put one inside of the other.
2

There's a lot going on here and most of the code results from going against the grain when writing Ruby. Using instance_variable_get should be an absolute last resort. It's considered highly rude to just reach into an object and pull out a variable. It creates ugly and undesirable inter-dependencies. If that other object wanted to give you that value it would have a method to access it.

The way I see it what you're trying to do boils down to something like this:

def highest_frequency
  @analyzers.map do |a|
    a.highest_wf_count
  end.sort.last
end

Let Analyzer implement highest_wf_count as a method, even if it's just an attr_reader. This gives you the flexibility to change how and when that value is computed. Maybe you don't need to do it when the object is initialized. Maybe it's done in another thread, or it's evaluated lazily.

Whenever possible try and structure your code as a series of straight-forward transformations. Try not to create convoluted, branching, ugly comparisons. Lean on Enumerable whenever possible, it's usually got a method that does exactly what you want, or two that in conjunction do the job perfectly.

Comments

1

This is way more complex than it needs to be (or should be).

Why does Solution subclass LineAnalyzer? And why are you using instance_variable_get? You should define getter methods using attr_reader on the LineAnalyzer class so you can call methods instead of using instance_variable_get, which is a brute force approach that should only be used as a last resort.

I think you should fix this before proceeding.

When you have instance methods created with attr_reader, calculating the max becomes very simple:

highest_count_across_lines = @analyzers.map(&:highest_wf_count).max

I think your error probably is caused by these lines:

 @highest_count_words_across_lines << @analyzers.each do
            |a| a.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
        end .instance_variable_get(:@highest_wf_words)

I suggest simplifying this code, and the error will probably present itself to you. Did you really mean to append the value returned by each to @highest_count_words_across_lines? This will be an Array of analyzers. The Array class, of course, does not have a variable named :@highest_wf_words.

Again, I think you really need to simplify this code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.