each block create a Nil class - ruby-on-rails

I want calculate components of an average
Controller
def set_average_course
#course = #group.courses.find(params[:course_id])
#evaluations = #course.evaluations
#evaluations.each do |evaluation|
#numerator += evaluation.average * evaluation.coefficient
#denumerator += evaluation.coefficient
end
#average = #numerator / #denumerator
#course.update(average: average)
end
Logs
NoMethodError (undefined method `+' for nil:NilClass)
But
#numerator += evaluation.average * evaluation.coefficient
is well defined outside the .each block

It would be better and more efficient to compute the values using SQL:
The code will look like this:
def set_average_course
#course = #group.courses.find(params[:course_id])
res = Evaluation.select("SUM(Evaluations.average * Evaluations.coefficient) AS numerator, SUM(Evaluations.coefficient) AS denumerator").
where(course_id: #course.id)
average = res.first['numerator'] / res.first['denominator'] # Raise an error if 0
#course.update(average: average)
end
Hope this leads you to the right direction

When you enter the each loop for the first time, #numerator and #denumerator are not initialized yet. Instance variables are different from local variables in that they evaluate to nil if not initialized yet, whereas a reference to an uninitialized local variable will thrown an error. The solution is to initialize the variables to the neutral element of addition, which is 0, before entering the loop:
def set_average_course
#course = #group.courses.find(params[:course_id])
#evaluations = #course.evaluations
#numerator = 0
#denumerator = 0
#evaluations.each do |evaluation|
#numerator += evaluation.average * evaluation.coefficient
#denumerator += evaluation.coefficient
end
#average = #numerator / #denumerator
#course.update(average: average)
end
Although, as a side note, I think you mean "denominator" instead of "denumerator". You will also have to account for the case where #denumerator is equal to 0, for example, when #evaluations is empty:
def set_average_course
#course = #group.courses.find(params[:course_id])
#evaluations = #course.evaluations
return if #evaluations.blank? # or raise an error
#numerator = 0
#denumerator = 0
#evaluations.each do |evaluation|
#numerator += evaluation.average * evaluation.coefficient
#denumerator += evaluation.coefficient
end
#average = #numerator / #denumerator
#course.update(average: average)
end

Try to initialize numerator and denumerator to number like #p11y's answer.
My suggestion is to calculate average more ruby way like this:
#numerator = #evaluations.map { |e| e.average * e.coefficient }.reduce(&:+)
#denumerator = #evaluations.map { |e| e.coefficient }.reduce(&:+)
#average = #numerator / #denumerator

Related

Unable to declare a new function in lua, compiler tells me to include an '=' sign near the name of the function

So i have this Util.lua file in which i am making all the functions which will be used across all the states of my game.
This is what my Util File is like
function GenerateQuads(atlas, tilewidth, tileheight)
local sheetWidth = atlas:getWidth() / tilewidth
local sheetHeight = atlas:getHeight() / tileheight
local sheetCounter = 1
local spritesheet = {}
for y = 0, sheetHeight - 1 do
for x = 0, sheetWidth - 1 do
spritesheet[sheetCounter] =
love.graphics.newQuad(x * tilewidth, y * tileheight, tilewidth,
tileheight, atlas:getDimensions())
sheetCounter = sheetCounter + 1
end
end
return spritesheet
end
function table.slice(tbl, first, last, step)
local sliced = {}
for i = first or 1, last or #tbl, step or 1 do
sliced[#sliced+1] = tbl[i]
end
return sliced
end
funtion GenerateQuadsPowerups()
local counter = 1
local quads = {}
return counter
end
note that the last function didn't work at all so i just returned counter for testing, the error message given is :
'=' expected near 'GenerateQuadsPowerups'
"Powerup" is a class i declared using a library class.lua. When i removed the problematic function from Util.lua, the same error was given on the first function i made in the Powerup.lua file.
Here's the class in case it is needed for reference
Powerup = Class{}
funtion Powerup:init()
self.x = VIRTUAL_WIDTH
self.y = VIRTUAL_HEIGHT
self.dx = 0
self.dy = -10
end
-- we only need to check collision with the paddle as only that collisionis relevant to this class
function Powerup:collides()
if self.x > paddle.x or paddle.x > self.x then
return false
end
if self.y > paddle.y or self.y > paddle.y then
return false
end
return true
end
funtion Powerup:update(dt)
self.y = self.y + self.dy * dt
if self.y <= 0 then
gSounds['wall-hit']:play()
self = nil
end
end
I can't understand what's going on here
Typo 1
funtion GenerateQuadsPowerups()
Typo 2
funtion Powerup:init()
Typo 3
funtion Powerup:update(dt)
self = nil achieves nothing btw. I guess you thought you could somehow destroy your PowerUp that way but it will only assign nil to self which is just a variable local to Powerup:update. It will go out of scope anyway.

How can I make query simpler?

I am creating a Rails 5 app.
In this app I got a method that gets values from child objects and adds them to an hash. The below method/code works perfectly fine but I how can I make it better in terms of speed and structure?
def generated_values(period, year, month, quarter)
count = 0
score = 0
actual = 0
goal = 0
red = 0
if stype == "measure"
measures.period(period, year, month, quarter).each do |measure|
count += 1
score += measure.score
actual += measure.value_actual
goal += measure.value_goal
red += measure.value_redflag
end
elsif stype == "objective"
children.each do |child|
child.measures.period(period, year, month, quarter).each do |measure|
count += 1
score += measure.score
actual += measure.value_actual
goal += measure.value_goal
red += measure.value_redflag
end
end
elsif stype == "scorecard"
children.each do |child|
child.children.each do |child2|
child2.measures.period(period, year, month, quarter).each do |measure|
count += 1
score += measure.score
actual += measure.value_actual
goal += measure.value_goal
red += measure.value_redflag
end
end
end
end
values = { :score => score == 0 ? 0 : (score / count).round, :actual => actual, :goal => goal, :red => red }
end
I think I would be tempted to do something like:
def generated_values(period, year, month, quarter)
case stype
when "measure"
selected_measures = measures
when "objective"
selected_measures = child_measures
when "scorecard"
selected_measures = grandchild_measures
end
count = selected_measures.count
{
score: count > 0 ? (selected_measures.sum(:score)/count).round : 0,
actual: selected_measures.sum(:value_actual)
goal: selected_measures.sum(:value_goal)
red: selected_measures.sum(:value_redflag)
}
end
Untested and off-the-cuff.
Naturally, the most interesting part is the selected_measures = bits. But, you haven't provided enough information to help with the proper formulation of those queries.

how to compare complex decimal number with integer value

I'm going to get all clinics that are near to my latitude and longitude. i did that with following method. the result of dist is a long value that i need to compare it with a integer value. i don't know why i get this error during the compare dist and distance which is a integer value.
this is my error:
NoMethodError (undefined method `<=' for (-2.693846638591123+0.0i):Complex):
and this is what everyhting that i did for this:
def get_clinic_list
ulat=params[:lat]
ulang=params[:lang]
distance=params[:distance]
#clinic=[]
Clinic.all.each do |clinic|
if clinic_distance(ulat,ulang,distance,clinic.id)
#doctor=DoctorProfile.find_by(user_id: clinic.user_id)
end
end
end
def clinic_distance(ulat, ulang,distance,clinic)
#clinic=Clinic.find(clinic)
diff_lat= ulat.to_f - #clinic.latitude.to_f
diff_lang= ulang.to_f - #clinic.longitude.to_f
#disc=Math.sqrt(((diff_lat*119.574)**2)+(diff_lang * Math.cos(diff_lat) * 111.320))
a=(diff_lat * 119.574) ** 2
b= diff_lang * Math.cos(diff_lat) * 111.320
c=a+b
logger.info "the c parameter is #{c}"
dist=Math.sqrt(c)
dist = dist ** 2
if dist <= distance
return true
else
return false
end
end
Complex numbers don't support <= or >= (although they do support ==)
Simplest solution is to get the absolute part of the number
if dist.abs <= distance
There was a mistake is pretty much every line of your clinic_distance method. I tried my best at correcting it, but I cannot test it without your data.
The problem isn't about Complex numbers. I don't know where this Complex number comes from, possibly from a negative c in your Math.sqrt(c).
EarthRadius = 6371 # km
OneDegree = EarthRadius * 2 * Math::PI / 360 # 1° latitude in km
def get_clinic_list
lat = params[:lat]
lon = params[:lang] # :lang???
max_distance = params[:distance] # :distance should probably be :max_distance
#clinic = [] # What do you do with this empty array?
Clinic.all.each do |clinic|
if distance_in_km(lat, lon, clinic.latitude, clinic.longitude) < max_distance
# Do you really want to keep overriding #doctor every time a clinic is found?
#doctor = DoctorProfile.find_by(user_id: clinic.user_id)
end
end
# You return every clinic, even ones far away...
end
def distance_in_km(lat1, lon1, lat2, lon2)
diff_lat = lat1.to_f - lat2.to_f
diff_lon = lon1.to_f - lon2.to_f
lat_km = diff_lat * OneDegree
lon_km = diff_lon * OneDegree * Math.cos(lat1.to_f * Math::PI / 180) # Math.cos expects a radian angle
Math.sqrt(lat_km**2 + lon_km**2)
end

How to return value without terminating the function?

Here it returns 0.2 because it stops the function without waiting for the iteration of the timer.
function Ani.Speed(maxSpeed, phase)
if(phase == accelerate) then
function speedUp()
if(maxSpeed ~= 0) then
maxSpeed = 0
end
returnedSpeed = maxSpeed + 0.2
return(returnedSpeed)
end
timer.performWithDelay(1000, speedUp, 10)
end
end
How to return the maxSpeed at each iteration?
Expected result:
print(maxSpeed) -- 0/0.2/0.4/0.6/(...)/2, where "/" is interval in second
Declare a local array variable before timer.performWithDelay and add all maxSpeed to the array inside speedUp function. After timer.performWithDelay, return the array.
As requested, please find below the suggested code:
if(phase == accelerate) then
returnedSpeed = []
i = 0 #(array index)
function speedUp()
if(maxSpeed ~= 0) then
maxSpeed = 0
end
returnedSpeed[i] = maxSpeed + 0.2
i = i + 1
end
timer.performWithDelay(1000, speedUp, 10)
return(returnedSpeed)
end

self.method (params) Rails

I'm newbie and I would like to know if is it possible to define model methods with params. I mean. I have this method to calculate distances using spherical coordinates
#in my model
#Haversin formula to calculate distance between spherical coordinates
def self.distance(b)
rad_per_deg = Math::PI/180 # PI / 180
rkm = 6371 # Earth radius in kilometers
#rm = rkm * 1000 # Radius in meters
a=[]
a.push(self.lat)
a.spuh(self.long)
dlon_rad = (b[1]-a[1]) * rad_per_deg # Delta, converted to rad
dlat_rad = (b[0]-a[0]) * rad_per_deg
lat1_rad, lon1_rad = a.map! {|i| i * rad_per_deg }
lat2_rad, lon2_rad = b.map! {|i| i * rad_per_deg }
a = Math.sin(dlat_rad/2)**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad/2)**2
c = 2 * Math.asin(Math.sqrt(a))
distance=rkm * c
return distance
end
I want this to work like: obj.distance(b) where b is an array of latitude and longitude. But when I try this on irb I get:
NoMethodError: undefined method `distance' for #<Object:0x000000058854c8>
Probably I'm missing something.
class Meteo < ActiveRecord::Base
attr_accessible :date, :humidity, :lat, :long, :pressure, :temp, :town, :wind, :wind_direction
, :rain_quantity
#Haversin formula to calculate distance between spheric coordinates
def self.distance(b)
rad_per_deg = Math::PI/180 # PI / 180
rkm = 6371 # Earth radius in kilometers
#rm = rkm * 1000 # Radius in meters
a=[]
a.push(self.lat)
a.spuh(self.long)
dlon_rad = (b[1]-a[1]) * rad_per_deg # Delta, converted to rad
dlat_rad = (b[0]-a[0]) * rad_per_deg
lat1_rad, lon1_rad = a.map! {|i| i * rad_per_deg }
lat2_rad, lon2_rad = b.map! {|i| i * rad_per_deg }
a = Math.sin(dlat_rad/2)**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad/2)
**2
c = 2 * Math.asin(Math.sqrt(a))
distance=rkm * c
return distance
end
end
And I call this on irb like:
irb> m=Meteo.last
irb> b=[86.43971008189519, 23.477053751481986]
irb> m.distance(b)
Just remove self.
When you write def self.distance, you mean that the method will be called on the model class. You should use def distance if you want the method to be called on a model instance.
Compare:
class SomeModel
def self.distance
# ...
end
end
SomeModel.distance
With:
class SomeModel
def distance
# ...
end
end
obj = SomeModel.new
obj.distance
If I get you right, you are defining a class method (with def self.distance) but are calling it on an instance of that class (obj.distance(array)).
You should call the method on obj's class e.g. Meteo.distance(array).
Or simply define it as an instance method, by just leaving the self in method definition.
Hope, that helps

Resources