Rails add elements to array - ruby-on-rails

I have a method to calculated the average for a given set of records:
input = params[:recommendation_ratings].values # The params are sent from radio_tags in my view.
input.each do |mini_params|
rating_id = mini_params[:rating_id]
l = Rating.find(rating_id) #Find record on Rating table.
l.rating #Get value associated with rating_id
total_rating = []
total_rating << l.rating
average = total_rating.inject{ |sum, el| sum + el }.to_f / total_rating.size
puts average
end
l.rating is not being appended to the total_rating array. The puts average is being printed as:
3.0
3.0
3.0
3.0
3.0
How do I append each of the ratings being returned to the array to calculated the average,and other math functions.

try:
total_rating = []
input.each do |mini_params|
rating_id = mini_params[:rating_id]
l = Rating.find(rating_id) #Find record on Rating table.
total_rating << l.rating
end
average = total_rating.sum / total_rating.size.to_f

this should solve your issue but there is a better way
total_rating = []
input.each do |mini_params|
rating_id = mini_params[:rating_id]
l = Rating.find(rating_id) #Find record on Rating table.
total_rating << l.rating
average = total_rating.inject(:+).to_f / total_rating.size
puts average
end
So given an array of ids, try the following
Rating.where(id: mini_params[:rating_id]).average(:rating)
UPDATE: fixing the one line version
rating_ids = input.map { |mini_params| mini_params[:rating_id] }
Rating.where(id: rating_ids).average(:rating)

You need to first get all of the ratings you are trying to average. I'm assuming you have already done this, and all of those ratings are stored in total_rating. Then you need to add the specific rating to that array:
rating_id = mini_params[:rating_id]
l = Rating.find(rating_id)
total_rating << l
average = total_rating.sum.to_f / total_rating.size
puts average

Related

How to feed a dictionary to a Flux model in Julia

So I have a 20000x4 dataset, where the 4 columns have strings. The first is a description and the other three are categories, the last one being the one I wish to predict. I tokenized every word of the first column and saved it in a dictionary, with his respective Int value, and I changed the other columns to have numerical values. Now I'm having trouble to understand how to feed these data in a Flux model.
According to the documentation, I have to use a "collection of data to train with (usually a set of inputs x and target outputs y)". In the example, it separates the data x and y. But how can I make that with a dictionary plus two numeric columns?
Edit:
Here is a minimal example of what I have right now:
using WordTokenizers
using DataFrames
dataframe = DataFrame(Description = ["It has pointy ears", "It has round ears"], Size = ["Big", "Small"], Color = ["Black", "Yellow"], Category = ["Dog", "Cat"])
dict_x = Dict{String, Int64}()
dict_y = Dict{String, Int64}()
function words_to_numbers(data, column, dict)
i = 1
for row in range(1, stop=size(data, 1))
array_of_words = tokenize(data[row, column])
for (index, word) in enumerate(array_of_words)
if haskey(dict, word)
continue
else
dict[word] = i
i += 1
end
end
end
end
function categories_to_numbers(data, column, dict)
i = 1
for row in range(1, stop=size(data, 1))
if haskey(dict, data[row, column])
continue
else
dict[data[row, column]] = i
i += 1
end
end
end
words_to_numbers(dataframe, 1, dict_x)
categories_to_numbers(dataframe, 4, dict_y)
I want to use dict_x and dict_y as my input and output for a Flux model
Consider this example:
using DataFrames
df = DataFrame()
df.food = rand(["apple", "banana", "orange"], 20)
multiplier(fruit) = (1 + (0.1 * rand())) * (fruit == "apple" ? 95 :
fruit == "orange" ? 45 : 105)
foodtoken(f) = (fruit == "apple" ? 0 : fruit == "orange" ? 2 : 3)
df.calories = multiplier.(df.food)
foodtoken(f) = (fruit == "apple" ? 0 : fruit == "orange" ? 2 : 3)
fooddict = Dict(fruit => (fruit == "apple" ? 0 : fruit == "orange" ? 2 : 3)
for fruit in df.food)
Now we can add the token numeric values to the dataframe:
df.token = map(x -> fooddict[x], df.food)
println(df)
Now you should be able to run the prediction with df.token as an input and df.calories as an output.
========== addendum after you posted further code: ===========
With your modified example, you just need a helper function:
function colvalue(s, dict)
total = 0
for (k, v) in dict
if occursin(k, s)
total += 10^v
end
end
total
end
words_to_numbers(dataframe, 1, dict_x)
categories_to_numbers(dataframe, 4, dict_y)
dataframe.descripval = map(x -> colvalue(x, dict_x), dataframe.Description)
dataframe.catval = map(x -> colvalue(x, dict_y), dataframe.Category)
println(dataframe)

Lua Acessing table values within nested table

I'm trying to test certain variables on a grid made out of nested tables. However no matter what I try it wont give me the values stored within the variables only the data type or a nil value
y = {}
for _y = 0,16 do
for _x = 0,16 do
x = {}
x.x = _x
x.y = _y
x.v = flr(rnd(2))
if x.x < 1 or x.x > 14 then
x.v = 3
end
if x.v == 0 then
x.v = "."
elseif x.v ==1 then
x.v = ","
else
x.v = "0"
end
add(y,x)
end
end
I've tried accessing the value using
print(t[1][3])
But this only prints back a nil value, how would I code this to show whats stored within the value within these two tables?
You have the nesting as follows:
y = {x_1, x_2, x_3, ...}
where, each of x_i is of the form:
x = {
x = p,
y = q,
v = r
}
so, you will have the indexing for each x element as y[i], and each y[i] contains 3 attributes:
print(y[1].x)
will give you x_1.x
You want to create a 2-dimensional table, but only create a 1-dimensional one.
Fix your code to look somewhat like this
y = {}
for _y=1,16 do
y[_y] = {}
for _x=1,16 do
y[_y][_x]= "your data"
end
end

Random sum of elements in an array equals to y - ruby [duplicate]

This question already has answers here:
Finding all possible combinations of numbers to reach a given sum
(32 answers)
Closed 6 years ago.
Need to create an array whose sum should be equal to expected value.
inp = [1,2,3,4,5,6,7,8,9,10]
sum = 200
output:
out = [10,10,9,1,3,3,3,7,.....] whose sum should be 200
or
out = [10,7,3,....] Repeated values can be used
or
out = [2,3,4,9,2,....]
I tried as,
arr = [5,10,15,20,30]
ee = []
max = 200
while (ee.sum < max) do
ee << arr.sample(1).first
end
ee.pop(2)
val = max - ee.sum
pair = arr.uniq.combination(2).detect { |a, b| a + b == val }
ee << pair
ee.flatten
Is there any effective way to do it.
inp = [1,2,3,4,5,6,7,8,9,10]
sum = 20
inp.length.downto(1).flat_map do |i|
inp.combination(i).to_a # take all subarrays of length `i`
end.select do |a|
a.inject(:+) == sum # select only those summing to `sum`
end
One might take a random element of resulting array.
result = inp.length.downto(1).flat_map do |i|
inp.combination(i).to_a # take all subarrays of length `i`
end.select do |a|
a.inject(:+) == sum # select only those summing to `sum`
end
puts result.length
#⇒ 31
puts result.sample
#⇒ [2, 4, 5, 9]
puts result.sample
#⇒ [1, 2, 3, 6, 8]
...
Please note, that this approach is not efficient for long-length inputs. As well, if any original array’s member might be taken many times, combination above should be changed to permutation, but this solution is too ineffective to be used with permutation.
I found an answer of this question in the following link:
Finding all possible combinations of numbers to reach a given sum
def subset_sum(numbers, target, partial=[])
s = partial.inject 0, :+
#check if the partial sum is equals to target
puts "sum(#{partial})=#{target}" if s == target
return if s >= target #if we reach the number why bother to continue
(0..(numbers.length - 1)).each do |i|
n = numbers[i]
remaining = numbers.drop(i+1)
subset_sum(remaining, target, partial + [n])
end
end
subset_sum([1,2,3,4,5,6,7,8,9,10],20)

How do I create an average for a temperature data set?

I am writing a program which takes a set of data and then averages it. This data set is the average temperature at Laguardia Airport for every month which corresponds with a temperature.
Here is an example one data point:
2009-07,23.6
Which is year-month, temp.
I have 163 data points. All of the data points are in a .txt file, each on a new line.
I made the data into an array and split it. For some reason, my program says my average is 0 every time I try to run it
Here is my code:
data = File.open("avg_temp.txt", "r+")
contents = data.read
contents = contents.split("\r\n")
contents.collect! do |x|
x.split(',')
end
sum = 0
data.each do |x|
sum = sum + x[1].to_f
end
avg = sum / contents.length
puts avg
assign avg = sum/contents.length outside the loop after the end. Variables defined within a loop have a scope limited to that loop. Also you are looping over data, should be content
contents.each do |x|
puts x[1] # to check if the right value is being evaluated
sum = sum + x[1].to_f
end
avg = sum/contents.length
Your avg is not the top level local variable. Thus you can't access it from the top level. avg is scoped to the block only. You can do below :-
avg = 0
data.each do |x|
sum = sum + temp[1].to_f
avg = sum / contents.length
end
puts avg
sum = 0
data.each do |x|
sum = sum + temp[1].to_f
avg = sum / contents.length
end
puts avg
The avg variable is no longer in scope, as it's outside of the each block. To print the avg, simply move it inside of the block like so
sum = 0
data.each do |x|
sum = sum + temp[1].to_f
avg = sum / contents.length
puts avg
end
Or move the avg variable outside of the loop (to perform the action once, after your loop has exited)
sum = 0
data.each do |x|
sum = sum + temp[1].to_f
end
avg = sum / contents.length
puts avg
More info at http://rubyflare.com/2009/09/30/variables-scope-and-iterators/
I'd write this more simply:
lines = 0
sum = 0
File.foreach("avg_temp.txt") do |data|
sum += data.split(',').last.to_f
lines = $.
end
puts 'Average: %f over %d datapoints' % [sum / lines.to_i, lines]
# >> Average: 23.375000 over 4 datapoints
Which outputs:
Average: 23.375000 over 4 datapoints
Starting with "avg_temp.txt" looking like:
2009-07,23.6
2009-08,23.7
2009-09,23.6
2009-10,22.6
To 'splain it:
$. is the current line number. Each time through the loop it reassigns the last read line-number to lines so we know how many to divide by.
foreach reads line-by-line, so there's no need to split the file. That also explains why I use $. to keep track of the number of elements. It also means this could read a file containing millions or billions of values without a problem, where read would go to its knees.

Calculate letter grade using a series of grades

Noob to Ruby here. Working through some exercises and have hit a wall.
Exercise: Calculate the letter grade of a series of grades
Create a method get_grade that accepts an Array of test scores. Each score in the array should be between 0 and 100, where 100 is the max score.
Compute the average score and return the letter grade as a String, i.e., 'A', 'B', 'C', 'D', 'E', or 'F'.
I keep returning the error:
avg.rb:1: syntax error, unexpected tLBRACK, expecting ')'
def get_grade([100,90,80])
^
avg.rb:1: syntax error, unexpected ')', expecting $end
Here's what I have so far. I'd like to stick with the methods below or .join as I'm trying to work with the methods we're learning in class. So sum, inject, etc won't necessarily be helpful. And I apologize in advance for the specificity of the request :) I'm sure there's a way better way that is way less code, but I'm just trying to learn it this way to start.
def get_grade([100,90,80])
get_grade = (array[0] + array[1] + array[2]).to_i / array.length.to_i
case get_grade
when 90..100
"A"
when 80..90
"B"
when 70..80
"C"
when 60..70
"D"
when 0..60
"F"
else
"Error"
end
end
puts get_grade([100,90,80])
You can't just randomly dump an array literal like [100,90,80] into the parameter list of a function definition. Judging by the function body, I think you meant to accept a single parameter array:
def get_grade(array)
grade = (array[0].to_i + array[1].to_i + array[2].to_i) / array.length
case grade
# unchanged
end
end
A terse replacement of the big case statement, for fun:
def letter_grade( score ) # assumes that score is between 0 and 100 (not 0-1)
%w[F F F F F F D C B A][ (score/10.0).floor ] || 'A' # handles grades >=100
end
Or, for more granularity:
def letter_grade( score ) # score is between 0 and 100 (not 0-1)
grades = %w[F F F F F F F F F F F F F F F F F F D- D D+ C- C C+ B- B B+ A- A A+ A+]
grades[ (3.0*score/10).floor ]
end
Thanks for the help today! Here's what I ended up doing to make it work with more than just 3 arguments. I used an Array#each method. I imagine there's a more elegant solution out there, but it worked! Worked on this since 10:00 AM, greatly appreciate the help!
def get_grade(array)
sum = 0
array.each do |element|
sum += element
end
average = sum / array.length
if average >= 90
grade = "A"
elsif average >= 80
grade = "B"
elsif average >= 70
grade = "C"
elsif average >= 60
grade = "D"
elsif average >= 0
grade = "F"
else
"Error"
end
end
puts get_grade([70,80,80,90,100])
puts get_grade([100,80,90,11,20])
puts get_grade([30,20,10,60,75])
Remember that the max score is 100 (and it can be assumed that the min is 0).
def get_grade(array)
sum = 0
array.each do |x|
sum += x
end
average = sum / array.length
if average > 100
print "Grades must be no more than 100!"
elsif average >= 90
grade = "A"
elsif average >= 80
grade = "B"
elsif average >= 70
grade = "C"
elsif average >= 60
grade = "D"
elsif average >=0
grade = "F"
else
print "Grades must be no less than 0!"
end
grade
end
puts get_grade([100,90,80]) == "A"
puts get_grade([98,90,80]) == "B"
puts get_grade([80,80,80]) == "B"
puts get_grade([55,45,35]) == "F"
puts get_grade([101,100,104])
puts get_grade([-2,-3,-4])
Added a proc so that even if a user enters a score over 100 it won't be calculated into the average.
Also refactored the switch statements to one line each. Let me know if this helps. Good luck.
def get_grade array
scores_under_100 = Proc.new {|score| score <= 100 && score > 0}
scores = array.select(&scores_under_100)
average = scores.inject(:+) / scores.size
case average
when 90..100 then puts "A."
when 80..89 then puts "B."
when 70..79 then puts "C."
when 60..69 then puts "D."
else puts "F."
end
end
puts get_grade([100, 100, 90, 67, 85, 200, 290, 299, 299])

Resources