Table cell border - ruby-on-rails

This is the 2x2 table I need to generate:
r1c1 r1c2
r2c1 r2c1
----
In other words I should print the bottom border of the bottom right cell. This is my code:
show.pdf.prawn
#This is a two dimensional array:
my_array = [["r1c1","r1c2"],["r2c1",Prawn::Table::Cell.new(:text => "r2c2", :border_width => 1 , :borders => :bottom)]]
#Table
pdf.table my_array, :border_width => 0
Well, with this code I have a 2x2 table with no borders!
Has someone any tip?

Here one solution better known as workaround:
#This is a two dimensional array:
my_array = [["r1c1","r1c2"],["r2c1",Prawn::Table::Cell.new(:text => "r2c2", :border_width => 1 , :borders => [:bottom])]]
#Table
pdf.table my_array,
#:headers => ["h1","h2"],
:border_style => :underline_header
Omitting headers => ["h1","h2"] you avoid the underlined header.

Related

Ruby Unable to map values to array of hash, searching for alternative

I have an array of hashes:
data1 = [{:first => 1, :second => 'whatever'},{:first => 2, :second => 'something'}]
test_merge = {'whatever' => {:third => 1, :fourth => 1}, 'something' => {:third => 2, :fourth => 2}}
I want this output:
[{:first=>"MODIFIED", :second=>"whatever", :test_field=>"added", :third=>1, :fourth=>1, "sdsds"=>"sdsds", "2x4"=>8}, {:first=>"MODIFIED", :second=>"something", :test_field=>"added", :third=>2, :fourth=>2, "sdsds"=>"sdsds", "2x4"=>8}]
I did map and merge:
data2 = data1.map do |d|
d[:test_field] = 'added'
d[:first] = 'MODIFIED'
d2 = test_merge[d[:second]]
d = d.merge(d2)
d['sdsds'] = 'sdsds'
d['2x4'] = 2*4
end
I got:
data1 #=> [{:first=>"MODIFIED", :second=>"whatever", :test_field=>"added"}, {:first=>"MODIFIED", :second=>"something", :test_field=>"added"}]
data2 #=> [8, 8]
This can be fixed if I do
data2 = data1.map do |d|
d[:test_field] = 'added'
d[:first] = 'MODIFIED'
d2 = {:test_field_two => 'notadded'}
d = d.merge(d2)
d['sdsds'] = 'sdsds'
d['2x4'] = 2*4
d #or d=d
end
But why do I have to insert that d in the end (d or d=d)? It looks ugly to write d in the end. Isn't there an alternative way to do it, I want the exact output as mentioned above?
Edit: 3 Jan 2017 (Don't read this edit if you are reading the question for first time, everything is mentioned above)
I have to necessarily use merge inside the .map, because I have got another hash as follows:
test_merge = {'whatever' => {:third => 1, :fourth => 1}, 'something' => {:third => 2, :fourth => 2}}
which needs to be merged like this inside the .each (merge doesn't work in .each unfortunately so I have to use map) or .map
d = d.merge(test_merge[d[:second]])
Also '2x4' , :first and other keys are important which needs to be set/modified.
And if I need to modify d[:first] , it should get modified.
I tried .each as mentioned by steve,
data1 = [{:first => 1, :second => 'whatever'},{:first => 2, :second => 'something'}]
test_merge = {'whatever' => {:third => 1, :fourth => 1}, 'something' => {:third => 2, :fourth => 2}}
data1.each do |d|
d[:test_field] = 'added'
d[:first] = 'MODIFIED'
d2 = test_merge[d[:second]]
d = d.merge(d2)
d['sdsds'] = 'sdsds'
d['2x4'] = 2*4
end
And this is the result I got:
[{:first=>"MODIFIED", :second=>"whatever", :test_field=>"added"}, {:first=>"MODIFIED", :second=>"something", :test_field=>"added"}]
That is not my expected output. Is there any hack to this?
When doing a map with a block the last executed line of the block is what's returned in the new array.
So if the last line is...
d['2x4'] = 2*4
Then it's 2*4 (8) that's returned.
Setting the last line of the block to...
d
...means that the value of the d variable (the entire hash) is returned.
You don't need to use map if you just want to change the hashes and don't need an array returned. Use each instead. (Edited to take into account Eric's observation about shallow duplication).
data2 = data1.map{|d| d.dup}
data2.each do |d|
d[:test_field] = 'added'
d[:test_field_two] = 'notadded'
d['sdsds'] = 'sdsds'
d['2x4'] = 2*4
end
Hash#merge returns a merged Hash without changing the original one, so you can add new |key,value| pairs and return the desired hash directly :
data2 = data1.map do |h1|
h1.merge(:test_field => 'added',
:test_field_two => 'not_added',
'sdsds' => 'sdsds',
'2x4' => 2 * 4)
end
data2 is now :
[{:first=>1,
:second=>"whatever",
:test_field=>"added",
:test_field_two=>"not_added",
"sdsds"=>"sdsds",
"2x4"=>8},
{:first=>2,
:second=>"something",
:test_field=>"added",
:test_field_two=>"not_added",
"sdsds"=>"sdsds",
"2x4"=>8}]
while data1 still is :
[{:first=>1, :second=>"whatever"}, {:first=>2, :second=>"something"}]
I think this might be better! Though I am not really sure if i understood the question correctly. Hope this helps.
data1 = [{:first => 1, :second => 'whatever'},{:first => 2, :second => 'something'}]
d2 = {:test_field_two => 'notadded', "sdsds"=>"sdsds", "2x4"=>2*4}
data2 = data1.map do |d| d.merge(d2) end
#=> [{:first=>1, :second=>"whatever", :test_field_two=>"notadded", "sdsds"=>"sdsds", "2x4"=>8}, {:first=>2, :second=>"something", :test_field_two=>"notadded", "sdsds"=>"sdsds", "2x4"=>8}]

Ruby: get the max occurrences of many hashes depending their content

I usually count the max occurrences of an array of items (int) like this:
specialties_with_frequency = specialties.inject(Hash.new(0)) { |h,v| h[v] += 1; h }
#reference.specialty_id = specialties.max_by { |v| specialties_with_frequency[v] }
Today, I need to count the max occurrences of hashes content.
varietal is a database object containing these fields:
id, grape_id, percent
My duplicate object can have multiple varietals.
#duplicates.each do |duplicate|
duplicate.varietals.each do |varietal|
end
end
For example, browsings duplicates, I will have:
duplicate 1: varietals => {grape_id => 1}, {grape_id => 2}
duplicate 2: varietals => {grape_id => 3}
duplicate 3: varietals => {grape_id => 1}, {grape_id => 2}
duplicate 4: varietals => {grape_id => 3}, {grape_id => 5}
In this case, the accepted data will be:
{grape_id => 1}, {grape_id => 2}
because there are 2 occurrences browsing all duplicates.
I have no idea of how to explore the same values in all occurrences.
Thanks,
Alexandre
You can use the exact same code as before, only with varietals arrays as keys in your frequency hash. Just make sure the arrays are sorted so that the keys will be equal for the same content.
If the grape_id is the only field used for occurence checking, you can simplify a bit by mapping the array of varietals to an array of numbers, in which case your frequency builder will look like this:
specialties_with_frequency = #duplicates.inject(Hash.new(0)) do |h, duplicate|
grape_ids = duplicate.varietals.map { |v| v[:grape_id] }.sort
h[grape_ids] += 1; h
end
Given the example you provided, the value should now be:
{[1, 2]=>2, [3]=>1, [3, 5]=>1}
For arrays and hashes it’s better to use Enumerable#group_by:
with_freq = whatever.group_by { |v| v } # (&:itself) for ruby2.3
.map { |k, v| [k, v.count] }
.to_h
If you need some sophisticated algorithm for grouping, change { |v| v } to use this algorithm.

Set random Rails variable to not equal another random variable?

I have 2 instance variables in a Rails controller:
#stories = Post.tagged_with("test").all(:order => "RANDOM()", :limit => 1)
#stories2 = Post.tagged_with("test").where('post_id not in (?)', [#stories]).all(:order => "RANDOM()", :limit => 1)
I don't want the other instance variable to equal the other but they both have to be "random" (I know this technically isn't random). Is it possible to set a variable random except one value?
#stories, #stories2 = Post.tagged_with("test").all(order: "RANDOM()", limit: 2)
You could make the second query return 2, and do some logic to check for equivalency
#stories = Post.tagged_with("test").all(:order => "RANDOM()", :limit => 1)
#stories2 = Post.tagged_with("test").where('post_id not in (?)', [#stories]).all(:order => "RANDOM()", :limit => 1)
#stories2.delete_at(#stories[0] == #stories2[0] ? 0 : 1);
With the above code, if the single element from the first object is the same as that of the second, we delete it and use the other. If they are not the same, we delete the "extra" story we have in the second array. At the end, each instance variable will have one item in the array, and they will not be the same.

Intersect array of hashes with array of ids

I have an array of hashes, this is not an active record model. This array is of objects of type Person with properties of id, name, age. I have a second array of strings, ["john", "james", "bill"].
I am attempting to remove all objects in the array of hashes except for the ones who have names in the second array, essentially performing an intersect, but I'm having quite a few problems. Any suggestions? I'm not sure if my syntax is just off or if I'm thinking about this the wrong way. Obviously I can just iterate through but this seems like its probably not the best way to handle the situation.
http://www.ruby-doc.org/core-1.9.2/Array.html#method-i-select
arr1 = [{:id => 1, :name => "John"}, {:id => 2, :name => "Doe"}];
arr2 = ["Doe"];
intersect = arr1.select {|o| arr2.include? o[:name]} # you can also use select!
p intersect # outputs [{:name=>"Doe", :id=>2}]
Late to the party, but if arr1 :name is an array this works nicely:
arr1 = [{:id => 1, :name => ["John", "Doe"]}, {:id => 2, :name => ["Doe"]}];
arr2 = ["Doe"]
> intersect = arr1.reject{|o| (arr2 & o[:name]).empty?}
=> [{:id=>1, :name=>["John", "Doe"]}, {:id=>2, :name=>["Doe"]}] #output
> arr2 = ["John"]
> intersect = arr1.reject{|o| (arr2 & o[:name]).empty?}
=> [{:id=>1, :name=>["John", "Doe"]}] #output
or use select:
intersect = arr1.select{|o| !(arr2 & o[:name]).empty?}
To remove all objects in the array of hashes except for the ones who have names in the second array, you can do:
arr1.reject!{|o| (arr2 & o[:name]).empty?}

Ruby on Rails: Sum table column row values based on other column data

I have a table with columns 'id', 'resource_id', 'read_time', 'value' where 'value' is a float
What I am trying to accomplish is to return a list of records such that the 'value' of each record is the sum of all the records at a specific 'read_time' but having differing 'resource_id' values.
I am wondering if there is a clever way (ie not looping through all the entries) to accomplish this. Currently I am implementing something along these lines:
#aggregate_meters = []
#res_one_meters = Meter.find(:all, :conditions => ["resource_id = ?", 1])
#res_one_meters.each do |meter|
read_time = meter.read_time
value = meter.value
if res_two_meter = Meter.find(:first, :conditions => ["resource_id = ? AND read_time = ?", 2, read_time ])
value = value + res_two_meter.value
end
aggregate_meter = Meter.new(:read_time => read_time, :value => value, :resource_id => 3)
#aggregate_meters.push(aggregate_meter)
end
Thank you.
ActiveRecord::Calculate is your friend here. Letting you do exactly what you want with one database call. It returns a hash using the unique values in the column used in the group as keys.
Here's the code you wrote, rewritten to use sum.
values = Meter.sum(:value, :group => :read_time)
values.each do |read_time, value|
aggregate_meter = Meter.new(:read_time => read_time, :value => value, :resource_id => 3)
#aggregates_meter.push(aggregate_meter)
end

Resources