Rails getting an error '/' undefined method - ruby-on-rails

Hi I am find the average
This what I am trying to do
I have as set of variables which I am taking from db based upon user_id and company_id the variables are And I cannot added then and there because I need to display individual parameter in my show page and I also wanted to display their average
So I am trying to do as below
#r1=company_rating.collect(&:r1)
#r2=company_rating.collect(&:r2)
#r3=company_rating.collect(&:r3)
#r4=company_rating.collect(&:r4)
So I am doing it like
arr = [#r1,#r2,#r3,®r4]
#totalaverage= arr.sum.compact /arr.size
My array sample looks like [10,20,30,nil],[nil,nil,nil,nil],[30,40,50,60]
And If I have array all Nil then it should show be Nil
But I am getting an error undefined method `/' for # and Why I am doing compact is because I have sum of the nil values in that
So please help how do this.

First of all, you define arr as an array of arrays. #r1, #r2 etc. are all arrays and what [#r1, #r2, ...] does is just mixing them up in another array. You probably want to merge them, not include them in another array:
arr = #r1 + #r2 + #r3 + #r4
Second, you should call arr.compact first, then sum the contents up. Also, I'm not really sure about the sum method. I'd use reduce(&:+) instead. So, to answer your question, '/' fails because compact returns an Array, and you're trying to divide an Array to a number. This looks better:
arr = #r1 + #r2 + #r3 + #r4
#totalaverage = arr.compact.reduce(&:+) / arr.size
What Array#reduce(&:+) does is to apply the + operator between array members and return the value (not an array).
EDIT: arr.sum does work if you're using Ruby on Rails. Otherwise use arr.reduce(&:+) instead.

Do as below,which should work :
#totalaverage= arr.flat_map(&:compact).inject(:+) /arr.size.to_f
Actually #totalaverage is an array of array. Where each internal element(array) of #totalaverage can have nil values also(as you shown). So you need to remove those nil entries if any from the internal array of #totalaverage. And arr.map(&:compact) will do the same job.

Simplest way to do this if you're using Rails:
#totalaverage = a.flatten.compact.sum.to_f / a.flatten.compact.size if a.flatten.compact.present?
This will assign to #totalaverage the result or nil in case all the values are nil.

Related

Active record sum giving the wrong answer

Hi I'm working on a project and I have to get the sum of an attribute of a active record collection. So I used:
#total = #records.sum(:cost)
However this gives the wrong value, for example if I have:
#records.each{ |x| puts x.cost}
I get 118.80 and 108.00
but for #total I get 680.40, which obviously isn't the answer, however if I use:
#total = 0
#records.each{ |x| #total = #total + x.cost}
I get the right answer of 226.80
If anyone can help me understand what is going on here it would be greatly appreciated.
Be careful, as a record collection is an instance of ActiveRecord::Associations::CollectionProxy, not an Array. It means that if you call:
#object.collection.sum(:cost)
actually what gets called is this method: http://apidock.com/rails/v4.2.7/ActiveRecord/Calculations/sum
And it will call sum in the SQL database, so the result gets influenced by the parameters of the query, e.g. groups, joins, etc.
While if you want to use Array sum, as in here: http://apidock.com/rails/Enumerable/sum
You would have to make your object Array first, via to_a:
#object.collection.to_a.sum(&:cost)
try this:
pluck the values of attr cost into an array and aggregate their sum
#total = #records.pluck(:cost).sum

Array of Sql values in Ruby

in my Rails project I am trying to use the following query in a search form_tag
Student.joins(:courses).where(#params.joins(','), #values)
where params and values are dynamically constructed arrays since there are some optional parameters in the search. An example from my code:
if params[:date_begin] != ''
#params.push " courses.date_begin >= ? "
#values.push params[:date_begin]
end
The problem is the #values array is being considered as one argument and raises this error:
wrong number of bind variables (1 for 2)
How do I tell it to consider the array elements separately?
What about build query this way:
scope = Student.joins(:courses)
if params[:date_begin].present?
scope = scope.where(" courses.date_begin >= ? ", params[:date_begin])
end
scope
You need to splat array
Student.joins(:courses).where(#params.joins(','), *#values)
You can unpack the array like so:
Student.joins(:courses).where(#params.join('AND'), *#values)
(Note you also need to change joins to join and the comma to AND).

access values from multidimen array in ruby

Hi I have an array that i created using push like this
arr.push(h, s.power)
PS: h and s.power both are variables but depends on condition I applied
which ends up something like this
[22,"0.014",22,"0.01",22,"0.01",22,"0.082",22,"0.0002",22,"0.02822",22,"0.0042822",22,"0.041662",21,"0.0042822",21,"0.11107"]
but now I want to create new array for each new value like 22, 21 but I can not access it with many combinations I tried such as arr[22], with arr.map
You should consider using a Hash instead. See ruby hash documentation here.
So instead of pushing h and s.power into an array, you would add them to the hash like this:
my_hash[h] ||= []
my_hash[h].push(s.power)
The first line makes sure you have an array in the hash for the latest value of h. The second adds s.power to that array.
If you run this code repeatedly, you will end up with one array for each unique value of h which you can access like this:
my_hash[22] # <= returns the array of s.power values for h=22
my_hash[21] # <= returns the array of s.power values for h=21
If I understand your question correctly, this should be a clean way to do what you want.

rails to find the average of an parameters

I am trying to calculate the average of parameters by passing them to an array but I am getting the following error. So I have doubt am I doing it right?
Here is my code
arr= #r1+#r2+#r3+#r4+#r5
#current_user_satisfaction= arr.inject{ |sum, el| sum + el }.to_i / arr.size
Where I am getting r1, r2,r3,r4 from the DB.
I am getting the following error
: syntax error, unexpected tIDENTIFIER, expecting keyword_end #current_user satisfaction= arr.inject{ |sum, el| sum +... ^
What was my problem where is my error. I actually started learning ROR very recently.
This what I am writing to do
I have as set of variables which I am taking from db based up user_id and company_id
the variables are
#r1=company_rating.collect(&:r1)
#r2=company_rating.collect(&:r2)
#r3=company_rating.collect(&:r3)
#r4=company_rating.collect(&:r4)
And I wanted to find the avg of all those variables.
So I am doing it like arr = [#r1,#r2,#r3,®r4]
#current-user_satisfaction= arr.sum.compact /arr.size
But I am getting an error / is undefined and Why I am doing compact is because I have sum of the nil values in that
So please help how do this.
This is not an array!
arr= #r1+#r2+#r3+#r4+#r5
This is a sum. Should be arr= [#r1,#r2,#r3,#r4,#r5]
Additionally you missed dot between #current_user and satisfaction.
Also it is not as it should be done in rails. Could you show us how those variables are set?
First, You need to create the array like this
arr= [#r1,#r2,#r3,#r4,#r5]
The error you are getting is about the . dot you missed between #current_user and satisfaction. Change it accordingly and you will get it working.
As far as I think, you don't need an array there. if you are doing, arr= #r1+#r2+#r3+#r4+#r5, it is already calculating the sum of values, why you need to put them to array and go for a loop.
However, If you still want to use array, instead of arr.inject{ |sum, el| sum + el }, you can use arr.reduce('+'), which does the same thing of calculating sum of all array values. This has nothing to do with your problem, but makes your code more understandable.

How do I collect and combine multiple arrays for calculation?

I am collecting the values for a specific column from a named_scope as follows:
a = survey_job.survey_responses.collect(&:base_pay)
This gives me a numeric array for example (1,2,3,4,5). I can then pass this array into various functions I have created to retrieve the mean, median, standard deviation of the number set. This all works fine however I now need to start combining multiple columns of data to carry out the same types of calculation.
I need to collect the details of perhaps three fields as follows:
survey_job.survey_responses.collect(&:base_pay)
survey_job.survey_responses.collect(&:bonus_pay)
survey_job.survey_responses.collect(&:overtime_pay)
This will give me 3 arrays. I then need to combine these into a single array by adding each of the matching values together - i.e. add the first result from each array, the second result from each array and so on so I have an array of the totals.
How do I create a method which will collect all of this data together and how do I call it from the view template?
Really appreciate any help on this one...
Thanks
Simon
s = survey_job.survey_responses
pay = s.collect(&:base_pay).zip(s.collect(&:bonus_pay), s.collect(&:overtime_pay))
pay.map{|i| i.compact.inject(&:+) }
Do that, but with meaningful variable names and I think it will work.
Define a normal method in app/helpers/_helper.rb and it will work in the view
Edit: now it works if they contain nil or are of different sizes (as long as the longest array is the one on which zip is called.
Here's a method that will combine an arbitrary number of arrays by taking the sum at each index. It'll allow each array to be of different length, too.
def combine(*arrays)
# Get the length of the largest array, that'll be the number of iterations needed
maxlen = arrays.map(&:length).max
out = []
maxlen.times do |i|
# Push the sum of all array elements at a given index to the result array
out.push( arrays.map{|a| a[i]}.inject(0) { |memo, value| memo += value.to_i } )
end
out
end
Then, in the controller, you could do
base_pay = survey_job.survey_responses.collect(&:base_pay)
bonus_pay = survey_job.survey_responses.collect(&:bonus_pay)
overtime_pay = survey_job.survey_responses.collect(&:overtime_pay)
#total_pay = combine(base_pay, bonus_pay, overtime_pay)
And then refer to #total_pay as needed in your view.

Resources