I'm trying to create a Google chart using GoogleVisualr.
This input works:
data_table.add_rows([
['04/14', 1],
['04/15', 2],
['04/16', 3],
['04/17', 4],
['04/18', 5],
['04/19', 1],
['04/20', 12],
['04/21', 13],
['04/24', 14],
['04/14', 15],
['04/24', 16],
['04/22', 17],
['04/14', 18],
['04/4', 19],
])
I am currently using:
Product.find(:all, :order => "created_at ASC").each do |p|
data_table.add_rows([
[p.created_at.strftime("%m/%d"), p.rating]
])
which returns:
01/13
2
01/20
3
02/22
2
03/14
2
03/19
2
04/14
1
04/15
2
04/17
2
05/14
2
05/14
2
05/14
2
05/14
2...
How can I format my array to match what GoogleVisualr requires:
[ [data, value], [date, value]...]
No need to use a loop, just use map:
rows = Product.all.order("created_at ASC").map do |p|
[p.created_at.strftime("%m/%d"), p.rating]
end
data_table.add_rows(rows)
This code "Product.find(:all, :order => "created_at ASC")" you can create a :scope and your controller assigns #products = Product.order_by_created
#products.inject([]) do {|result, p| result << [p.created_at.strftime("%m/%d"), p.rating])}
Since you're already looping over each row, you can just use DataTable#add_row.
Product.find(:all, :order => "created_at ASC").each do |p|
data_table.add_row([p.created_at.strftime("%m/%d"), p.rating])
end
Make it into a string and interpolate your values within it.
puts "data_table.add_rows(["
Product.find(:all, :order => "created_at ASC").each do |p|
puts "['#{p.created_at.strftime("%m/%d")}', #{p.rating}],"
end
puts " ])"
Try something like this
pry(main)> result = []
=> []
pry(main)> Project.find(:all, :order => "created_at ASC").each do |p|
pry(main)* result << [p.created_at.strftime("%m/%d"), p.id]
pry(main)* end
pry(main)> result
=> [["02/05", 1],
["02/14", 6],
["02/15", 7],
["02/18", 8]]
Probably not the most efficient way, but premature optimisation is the root of all evil:
#products = Product.all(:order => 'created_at ASC')
#csv = CSV.generate do |csv|
csv << ["Secret", "Timestamp"]
#products.each { |secret|
csv << ["#{secret.story}", "#{secret.updated_at.strftime('%s')}"]
}
end
#csv
If you look at the Google Visualr API (https://github.com/winston/google_visualr) on Winston's Github page, you will see that the add_rows method requires a nested array, where each element of the array is another array of size (length) 2. The first element e[0] is the date and the second element e[1] is the data value for that date. Pass your data in this format, and it should work correctly.
It looks like your code should already be doing that, as far as we can tell from here without actually being on your machine. However, your code is calling the add_rows method for each iteration in your each method, and supplying the data_table.add_rows method with a nested array that only has one array inside of it.
So instead of looking like this:
[ ['04/14', 1],
['04/15', 2],
['04/16', 3],
['04/17', 4] ]
and calling add_rows just one time like you would normally do, you are calling add_rows over and over again like this:
add_rows ( [ ['04/14', 1] ] )
add_rows ( [ ['04/15', 2] ] )
add_rows ( [ ['04/16', 3] ] )
add_rows ( [ ['04/17', 4] ] )
once for each data point.
What you should do is use your each iterator to put each date and its corresponding data value into an array, then call add_rows with that array as the parameter. Something like this:
my_array = []
Product.find(:all, :order => "created_at ASC").each do |p|
my_array << [p.created_at.strftime("%m/%d"), p.rating]
end
data_table.add_rows(my_array)
I hope this helps.
Related
I have a hash, its values are 2 dimensional arrays, e.g.
hash = {
"first" => [[1,2,3],[4,5,6]],
"second" => [[7,88,9],[6,2,6]]
}
I want to access the elements to print them in xls file.
I did it in this way:
hash.each do |key, value|
value.each do |arr1|
arr1.each do |arr2|
arr2.each do |arr3|
sheet1.row(row).push arr3
end
end
end
end
Is there a better way to access each single element without using each-statement 4 times?
The desired result is to get each value from key-value pair as an array, e.g.
=> [1,2,3,4,5,6] #first loop
=> [7,88,9,6,2,6] #second loop
#and so on
hash = { "first" =>[[1, 2,3],[4,5,6]],
"second"=>[[7,88,9],[6,2,6]] }
hash.values.map(&:flatten)
#=> [[1, 2, 3, 4, 5, 6], [7, 88, 9, 6, 2, 6]]
Isn't it as simple as something like:
hash.each do |k,v|
sheet1.row(row).concat v.flatten
end
I have a two dimensional array with three fields in the second dimension.
Is it possible to use uniq on the first two fields of the second dimension?
I have seen array.uniq! {|c| c.first}. When I am correct, this apply uniq on the first field of the array.
Is it possible to use something like array.uniq! {|c| c.first c.second}?
#array = Array.new()
#array << Array.new([journal.from_account_number, journal.from_account,
journal.buchungsart])
There are several entries in #array.
The question was how to get unique values from array not considering journal.buchungsart.
The answer was: #array = #array.uniq! {|c| [c.first, c.second]}
Yes, put the values in an array:
array.uniq! {|c| [c.first, c.second]}
Just return an array of two elements in the block.
Since Array#second is not defined in the standard library, do
array.uniq! { |c| [c[0], c[1]] }
instead, which can be further simplified to array.uniq! { |c| c[0..1] }
You could also make use of the fact that hash keys are unique.
arr = [[1, 2, 3],
[2, 1, 4],
[1, 2, 5]]
a = arr.each_with_object({}) { |row, h| h.update(row.first(2)=>row) }.values
#=> [[1, 2, 5], [2, 1, 4]]
See Hash#update (aka merge!).
Before extracting the hash values with Hash#value, we have computed the following hash.
arr.each_with_object({}) { |row, h| h.update(row.first(2)=>row) }
#=> {[1, 2]=>[1, 2, 5], [2, 1]=>[2, 1, 4]}
Notice that, for given values of the first two elements in a row, it is the last row of arr with those values that is to be "kept". The first such row in arr is to be kept, use the following.
arr.each_with_object({}) { |row, h| h.update(row.first(2)=>row) { |_,o,_| o } }.values
#=> [[1, 2, 3], [2, 1, 4]]
This does not mutate arr. If arr is to be modified, write
arr.replace(a)
where a is defined above.
Array#first accepts a parameter :
%w(a b c d e f).first(2)
# => ["a", "b"]
so you could just use :
array.uniq!{ |c| c.first(2) }
First I get a collection of channels from my scope
Channel.not_archived.map { |c| channels << c }
Then I sort those by the start_time attribute:
channels.sort! { |a, b| a.start_time <=> b.start_time }
Then I want to group them by their start times. So channels that start at 8:00am will be grouped together. So I use the group_by method:
#grouped_channels = #channels.group_by { |c| time_with_offset(c).strftime("%I:%M %P") }
the time_with_offset method:
# Returns time with offset
def time_with_offset(channel)
user = current_user.time_zone.to_i
organization = channel.organization.time_zone.to_i
time_offset = organization -= user
channel.start_time - time_offset.hours
end
And I get back all of my records in the correct group. The issue i'm having is that the groups are not in order. So the group of 8:00am should be before the group of 9:00am. It's just in weird random order now. Can anyone help me get these in correct order?
If you wish to reorder the key-value pairs of any hash h in key order given by an array keys, which contains all the keys in the desired order, write
(keys.zip(h.values_at(*keys))).to_h
For Ruby versions prior to 2.0, write
Hash[keys.zip(h.values_at(*keys))]
For example,
h = { b: 1, d: 2, a: 3, c: 4 }
#=> {:b=>1, :d=>2, :a=>3, :c=>4}
keys = [:a, :b, :c, :d]
(keys.zip(h.values_at(*keys))).to_h
#=> {:a=>3, :b=>1, :c=>4, :d=>2}
The steps are as follows.
a = h.values_at(*keys)
#=> same as h.values_at(:a, :b, :c, :d)
#=> [3, 1, 4, 2]
b = keys.zip(a)
# => [[:a, 3], [:b, 1], [:c, 4], [:d, 2]]
b.to_h
#=> {:a=>3, :b=>1, :c=>4, :d=>2}
First you are sorting by one time, then you are grouping by a different time. I expect this explains your undesired order.
Sort by the offset time.
channels.sort_by { |c| time_with_offset(c) }.group_by { |c| time_with_offset(c).strftime("%I:%M %P") }
I've tried to insert some Values into this hash were every key is an array but when I print all result just the last value
def self.hash_builder(query)
statistic = Hash.new { |hash, key| hash[key] = [] }
if !query.empty?
query.each do |q|
statistic[:sell].push(q.total_sell.to_i)
statistic[:price].push(q.total_price.to_f)
end
else
statistic[:sell].push(0)
statistic[:price].push(0.0)
end
return statistic
end
I call this method after make a query, and I send to this the query with the new params, but every time i see inside this hash just the last query value
THIS IS THE RESULT
I'll answer here because the comment section doesn't allow enough room. You're wrong about <<. It ought to work fine.
$ irb
irb(main):001:0> s = Hash.new {|h, k| h[k] = [] }
=> {}
irb(main):002:0> s[:sell] << 1
=> [1]
irb(main):003:0> s[:sell] << 2
=> [1, 2]
irb(main):004:0> s[:sell]
=> [1, 2]
irb(main):005:0> s[:price]
=> []
But push should work, too.
irb(main):006:0> s[:sell].push(3)
=> [1, 2, 3]
Ok so I have a sale model that
recent_sales = Sale.recent
=> [#<Sale id: 7788, contact_id: 9988, purchasing_contact_id: 876, event_id: 988, #<BigDecimal:7fdb4ac06fe8,'0.0',9(18)>, fulfilled_at: nil, skip_print: nil, convention_id: 6, refund_fee: #<BigDecimal:7fdb4ac06de0,'0.0',9(18)>, processing: false>, #<Sale id: 886166, , contact_id: 7775,
recent_sales.count
=> 32
I know i can do this
grouped_sales = recent_sales.group_by(&:contact_id).map {|k,v| [k, v.length]}
=> [[9988, 10], [7775, 22]]
But what i really need is not just grouping on contact_id but also event_id so the final results looks like this
=> [[9988, 988, 5], [9988, 977, 5], [7775, 988, 2], [7775, 977, 20]]
so i have the event_id and the grouping is splitting them up correctly...any ideas on how to do this
I tried
recent_sales.group('contact_id, event_id').map {|k,v| [k, k.event, v.length]}
but no go
grouped_sales = recent_sales.group_by { |s| [s.contact_id, s.event_id] }
.map { |k,v| [k.first, k.last, v.length] }
Simply, try
group(['contact_id','event_id'])
It worked for me. So, I posted as answer to help others as well.
Ask the database to do the grouping
grouped_sales = recent_sales.group([:contact_id, :event_id]).count
the result is a hash each key is an array of the contact and event id, and the value is the count.
So if you want arrays of three
grouped_sales = recent_sales.group([:contact_id, :event_id]).count.map{ |k,v| k << v }