Subtract current item with next indexed item - ruby-on-rails

I'm trying to subtract the current item in the loop with the next indexed item, but I'm just getting the following error: undefined method `[]' for 0.0:Float
<% #trial.methods.each_with_index do |e, index| %>
<%= (e.total - e.total[index+1]) %><br />
<%= Time.at(e.try(:assessment).try(:assessment_date)/1000).strftime("%d/%m/%Y") %><br />
<%= e.try(:assessment).try(:degrees) %>
<% end %>

I think there is an easier way of doing that. Look at the following example.
# An array of 5 random numbers
a = [7,12,1,2,3]
# Iterate through the indices of the array
a.each_index do |i|
# We only show the result of a[i+1] - a[i]
# given i+1 is still in range of the array
puts "#{a[i+1] - a[i]}" if (i+1) < a.length
end
This should output 5 -11 1 1 each on a new line.
Similarly, you could do something like this:
<% #trial.methods.each_index do |i| %>
<% if i + 1 < e.total.length %>
<%= (e.total[i] - e.total[index+1]) %>
<% else %>
<%= 0 %>
<% end %>
<% end %>

Use #each_cons to build a subarray of consecutive pairs, then map it:
array = [7,12,1,2,3]
array.each_cons(2).map{ |e| e.last - e.first }
# => [5, -11, 1, 1]
A slight alternative:
array.each_cons(2).map{ |a, b| b - a }
Of course, you can change to a - b or whatever you need.
The first part does this:
array.each_cons(2).each {|e| p e}
# => [7, 12]
# => [12, 1]
# => [1, 2]
# => [2, 3]

You can use Enumerable#reduce to achieve this:
a = [7,12,1,2,3]
a.reduce(&:-) # -11
So for your case:
#trial.methods.map{|e| e.total}.reduce(&:-)
See https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-reduce on its usage

Related

Rails traverse deep array of hashes

I got this very confusing array of hashes as an API response.
http://jsfiddle.net/PP9N5/
( the full response is massive. Posting only a part of it but it covers all elements of the response)
How can I get to "airlines".
I tried this
<% #flight["air_search_result"]["onward_solutions"]["solution"].each do|h| %>
<strong><%=h["pricing_summary"]["total_fare"] %></strong> -
<% h["flights"]["flight"]["segments"]["segment"].each do |s| %>
<%= s['airline'] %>
<% end %> <br> <hr>
<% end %>
And I get this error
can't convert String into Integer
I did some modifications like
<%= h["flights"]["flight"]["segments"]["segment"].first["airline"] %>
Error received - can't convert String into Integer
and
<%= h["flights"]["flight"]["segments"]["segment"][0]["airline"] %>
Error received - undefined method '[]' for nil:NilClass
Isnt there a simple way, like I say to find a key "airline" and for that key it returns its value. I stumbled upon this link, though I dont get any error, I also dont get any result.
Thanks.
UPDATE
I did this
<% h["flights"]["flight"]["segments"]["segment"].each do |o,p| %>
<% if o=="airline" %> <%= p %> <% end %>
<% end %> <br> <hr>
<% end %>
I can get few values of airlines where inside segment there is no array.
For eg, i can get where departure_date_time is 2014-07-07T07:10:00, index = 5.
http://jsfiddle.net/PP9N5/1/ (scroll down)
Here is some code you can add which will extract all keys equal the parameter in any Hash within your Hash:
class Hash
def deep_find(query, &block)
flat_map do |key, value|
if key == query
yield value if block_given?
[value]
elsif value.is_a? Hash
value.deep_find(query, &block)
elsif value.is_a? Array
value.select { |i| i.is_a? Hash }.flat_map { |h| h.deep_find(query, &block) }
end
end
end
end
Example:
hash = {"h" => [{ 'x' => [1, 5] }, { 'x' => 2 }, { 'f' => { 'x' => [3, 4] } }], 'x' => 6 }
hash.deep_find('x') { |x| puts "#{x}" }
# [1, 5]
# 2
# [3, 4]
# 6
# => [[1, 5], 2, [3, 4], 6]
it's a tipical problem :D
Replace "=>" for ":" and render.
your_json = {.....}
your_json.gsub("=>", ":")
puts your_json
You can validate a JSON before to work it with http://jsonlint.com/.

Transpose, Slice and Inject From Multipe Arrays

I don't know how appropriate title for this question.
Well, This is my problem
I have index action on homes_controller.rb looks like :
def index
#r = 2
#datas = [[1, 10], [2, 10], [3, 15], [4, 20], [5, 70], [6, 180], [7, 250], [8, 270], [9, 230], [10, 40], [11, 0], [12, 10]]
end
I want to result from above like this:
And on view looks like :
<table>
<thead>
<tr>
<th>Month</th>
<th>Forecast</th>
<th>Order</th>
<th>Begining Inventory</th>
<th>Ending Inventory</th>
</tr>
</thead>
<tbody>
<% ei = 0 %>
<% #datas.each_with_index do |d, index| %>
<tr>
<td><%= d[0] %></td>
<td><%= d[1] %></td>
<td><% if d[1] > bi %>
<% #datas.transpose.at(1).slice(index, #r).inject do |sum, s| -%>
<%= #biu = sum + s %>
<% end %>
<% end %>
</td>
<td><%= #bi = ei + #biu %></td>
<td><%= #ei = #bi - d[1] %></td>
</tr>
<% #biu = 0 %>
<% ei = #ei %>
<% end %>
</tbody>
</table>
State :
When the forecast d[1] is bigger than ei the calculation order #biu is 2 (#r) next of forecast.
Begining Inventory #bi is calculation from ei plus order #biu
Ending Inventory #ei is calculation from #bisubtracted with forecast d[1]
And then #ei put to ei
But the result like this :
I want 12th months must have : Order = 10, Begining invetory = 10, and Ending Inventory = 0
Your problem is here:
<% #datas.transpose.at(1).slice(index, #r).inject do |sum, s| -%>
<%= #biu = sum + s %>
<% end %>
When an array has only one item, inject without a starting value does not run the block at all:
puts [1,2].inject { |sum, s| puts 'was here!'; sum + s }
# was here!
# 3
puts [1].inject { |sum, s| puts 'was here!'; sum + s }
# 1
puts [1].inject(0) { |sum, s| puts 'was here!'; sum + s }
# was here!
# 1
If you add a starting value 0 to your code, though, #biu will be printed twice. To avoid that you need to move the assignment outside of the block:
<% #biu = #datas.transpose.at(1).slice(index, #r).inject do |sum, s| -%>
<% sum + s %>
<% end %>
<%= #biu %>
Or, more succinctly:
<%= #biu = #datas.transpose.at(1).slice(index, #r).inject(:+) %>

How to group an array of ActiveRecord objects?

I have an array:
<% #widgets.each do |w| %>
...
<% end %>
How can I display them in groups? Let's say by 4:
<div>1, 2, 3, 4</div>
<div>5, 6, 7, 8</div>
etc.
Thank you.
For the specific example you gave, you want each_slice:
<% #widgets.each_slice(4) do |ws| %>
<div><%= ws.join(', ') %></div>
<% end %>
You might also be interested in each_cons (each consecutive, e.g. "1,2,3", "2,3,4", "3,4,5", etc.) or group_by for arbitrary groupings.
Person = Struct.new(:name,:age,:male) do
def inspect
"<#{'fe' unless male}male '#{name}' #{age}>"
end
end
all = [
Person.new("Diane", 12, false),
Person.new("Harold", 28, true),
Person.new("Gavin", 38, true),
Person.new("Judy", 55, false),
Person.new("Dirk", 59, true)
]
p all.group_by(&:male)
#=> {
#=> false=>[ <female 'Diane' 12>, <female 'Judy' 55> ],
#=> true =>[ <male 'Gavin' 38>, <male 'Harold' 28>, <male 'Dirk' 59> ]
#=> }
p all.group_by{ |person| (person.age / 10) * 10 }
#=> {10=>[<female 'Diane' 12>],
#=> 20=>[<male 'Harold' 28>],
#=> 30=>[<male 'Gavin' 38>],
#=> 50=>[<female 'Judy' 55>, <male 'Dirk' 59>]}
Try to use each_slice(n):
require 'erb'
#widgets = (1..8).to_a
template = <<EOF
<% #widgets.each_slice(4) do |w| %>
<div><%= w.join(', ') %></div>
<% end %>
EOF
puts ERB.new(template).result(binding)
# =>
<div>1, 2, 3, 4</div>
<div>5, 6, 7, 8</div>

Accesing hash keys and attributes from the view

in an attempt to create a model with an array as an atribute, i ended up creating an array of hashes like so:
data1 = {}
data1[:name] = "Virtual Memory"
data1[:data] = #jobs.total_virtual_memory
data2 = {}
data2[:name] = "Memory"
data2[:data] = #jobs.total_memory
#data = []
#data << data1
#data << data2
which populates #data like this:
[{:data=>[#<Job day: "2010-08-02">, #<Job day: "2010-08-04">], :name=>"Virtual Memory"}, {:data=>[#<Job day: "2010-08-02">, #<Job day: "2010-08-04">], :name=>"Memory"}]
However i do not know how to acces these variables in the view. So as tu run somethig like:
for series in #data
series:name
for d in series:data
data:[Date, Value]
end
end
which would return something along the lines of:
Name1
Date1, Value1
Date2, Value 2,
Date3, Value 3,
Date4, Value 4,
Name2
Date1, Value 1,
Date2, Value 2,
Date3, Value 3,
Date4, Value 4,
This should work:
<% for series in #data %>
<%= series[:name] %>
<% for d in series[:data] %>
<%= d.date %>, <%= d.value %>
<% end %>
<% end %>
However you might consider using a more suitable datastructure instead of hashs. A Struct for example. This could look like this:
# in lib/JobData.rb:
JobData = Struct.new(:name, :data)
# in the controller:
data1 = JobData.new("Virtual Memory", #jobs.total_virtual_memory)
data2 = JobData.new("Memory", #jobs.total_memory)
#data = [data1, data2]
# in the view:
<% for series in #data %>
<%= series.name %>
<% for d in series.data %>
<%= d.date %>, <%= d.value %>
<% end %>
<% end %>
As a style point: I used for because you used for, but in general it's considered more rubyish to use each instead.
Here is the view:
<% for d in #data %>
{ pointInterval: <%= 1.day * 1000 %>,
name:<%= "'#{d[:name]}'"%>,
pointStart: <%= 2.weeks.ago.at_midnight.to_i * 1000 %>,
data: [
<% for chart in d[:data] %>
<%= "'[#{chart.day.to_time(:utc).to_i * 1000}, #{chart.data_attribute}],'" %>
<% end %>
]
},
<% end %>
Use #{d[:name]} to access the value of the "name" key and use d[:data] to access the array, then just loop throughthe array as if it were any normal array

How do you get the rows and the columns in the result of a query with ActiveRecord?

Is there a way with ActiveRecord to execute a custom SQL query and have it return an array of arrays where the first row is the column names and each following row is the row data? I want to execute something like:
connection.select_rows_with_headers "SELECT id, concat(first_name, ' ', last_name) as name, email FROM users"
And have it return:
[["id","name","email"],["1","Bob Johnson","bob#example.com"],["2","Joe Smith","joe#example.com"]]
This would allow me to print the results of the custom query in an HTML table like this:
<table>
<% result.each_with_index do |r,i| %>
<tr>
<% r.each do |c| %>
<% if i == 0 %>
<th><%=h c %></th>
<% else %>
<td><%=h c %></td>
<% end %>
<% end %>
</tr>
<% end %>
</table>
Note that select_all doesn't work because the keys in each hash are unordered, so you've lost the ordering of the results as specified in the query.
Not EXACTLY what you're looking for, but maybe:
connection.execute('select * from users').all_hashes
and you'll get back
[{:id => 1, :name => 'Bob', :email => 'bob#example.com'},{:id => 1, :name => 'Joe', :email => 'joe#example.com'}]
and you could do:
results = connection.execute('select * from users').all_hashes
munged_results = []
columns = results.first.keys.map(&:to_s)
munged_results << results.first.keys.map(&:to_s)
munged_results += results.map{|r| columns.map{|c| r[c]} }
something like that
edit:
results = connection.execute('select * from users').all_hashes
munged_results = []
columns = User.column_names
munged_results << columns
munged_results += results.map{|r| columns.map{|c| r[c]} }
That should be ordered properly.
Beyond that there is the result object that is returned from #execute that can be interrogated for bits of information. Methods like #fetch_fields get you the fields in order and #fetch_row will get you each row of the result set as an array (works like an iterator).
edit again:
OK, here's a good solution, modify for whatever DB you're using:
class Mysql::Result
def all_arrays
results = []
results << fetch_fields.map{|f| f.name}
while r = fetch_row
results << r
end
results
end
end
That will get them without a ton of overhead.
Use it like this:
connection.execute('select salt, id from users').all_arrays

Resources