Set random Rails variable to not equal another random variable? - ruby-on-rails

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.

Related

ruby group by hashes' values in hash

sorry about the title, cannot express myself better.
I have this:
{
7758 => { 3259 => 10, 39625 => 10, 36410 => 20, 36238 => 20, 34951 => 20, 32101 => 10},
7916 => { 3259 => 10, 39625 => 10, 36410 => 20, 36238 => 20, 34951 => 20, 32101 => 10},
8857 => { 1000 => 10, 39625 => 10 }
}
the keys of those hashes represents record ids, the values represent the data that should go in their row attribute.
problem is that this hash can weigh a lot, so it's imprudent to issue an update on the database for each record represented in the hash.
instead I thought about grouping up hashes with identical values and have a structure for which I can just issue an update to records in one shot.
comparing hashes values can be done even by transforming the nested hashes themselves into a json string, since it's the datatype we use for that column.
in the end I'd like to issue an update_all for a series of variants that has the same hash content, I understand that the number of updates issues to the database is 1:1 to how unique are the hash values, but I kinda have the choice to sort their keys in someway before the comparison should we have something smart to compare existing values rather than converting the content to a string for comparison purposes.
what happens now is a normal update on each hash record in a cycle:
UPDATE "table" SET "rates" = '{"3259":10,"39625":10,"36410":20,"36238":20,"34951":20,"32101":10}', WHERE "table"."variant_id" = 7758
UPDATE "table" SET "rates" = '{"3259":10,"39625":10,"36410":20,"36238":20,"34951":20,"32101":10}', WHERE "table"."variant_id" = 7916
UPDATE "table" SET "rates" = '{"1000":10,"39625":10}' WHERE "table"."variant_id" = 7916
I'd like to transform the original structure in something that allows me to perform this:
UPDATE "table" SET "rates" = '{"3259":10,"39625":10,"36410":20,"36238":20,"34951":20,"32101":10}', WHERE "table"."variant_id" IN(7758, 7916)
UPDATE "table" SET "rates" = '{"1000":10,"39625":10}' WHERE "table"."variant_id" = 7916
I tried a
hash.group_by { |h| h[1].to_json }.each do |rate|
but I have this in rate:
["{\"3259\":10,\"39625\":10,\"36410\":20,\"36238\":20,\"34951\":20,\"32101\
":10}", [[7758, {3259=>10, 39625=>10, 36410=>20, 36238=>20, 34951=>20,
32101=>10}], [7916, {3259=>10, 39625=>10, 36410=>20, 36238=>20,
34951=>20, 32101=>10}], [8857, {3259=>10, 39625=>1...
Maybe something like this:
result = hash.each_with_object({}) do |(id, attributes), result|
json_string = attributes.to_json
result[json_string] ||= []
result[json_string] << id
end
result.each do |json_string, ids|
# ...
end

Extract values from a string in Ruby

How to get a value from a string e.g
search_params[:price] = "1460,4500"
How can I get the first number into one variable and second into a different variable?
Did you mean this??:
first_price, second_price = search_params[:price].split(',')
You can use split method
irb(main):002:0> price = "1460,4500"
=> "1460,4500"
irb(main):003:0> price.split(',')
=> ["1460", "4500"]
irb(main):004:0> a, b = price.split(',')
=> ["1460", "4500"]
irb(main):005:0> a
=> "1460"
irb(main):006:0> b
=> "4500"

ordering array by elements

Im trying to arrange #plrdet by the values in arr.
when im selecting this way:
#plrdet = Player.find_all_by_fid(arr)
it returns in the order of the rows in the table, i want it to be ordered by the order of arr.
for example:
Player contains the following attributes: address, age, uniqnum.
and:
arr
is an array of the uniqnum.
arr=[456,123,789]
player=[{NYC,32,123},{BSAS,27,456},{LND,30,789})
the result that im looking for should be from the "find_all"
player=[,{BSAS,27,456},{NYC,32,123},{LND,30,789})
If I understand the problem I would try something like this:
Hash version
players = [{}]
#plrdet.each do |player|
players << {"adress" => player.adress, "age" => player.age, "fid" => player.fid}
end
players.inspect
Now result should be [{"adress" => BSAS, "age" => 27, "fid" => 456},{"adress" => NYC, "age" => 32,"fid" => 123},{"adress" => LND, "age" => 30, "fid" => 789}]
Array version
players = [[]]
#plrdet.each do |player|
players << [player.adress, player.age, player.fid]
end
Now result should be [[BSAS,27,456],[NYC,32,123],[LND,30,789]]
Sort
I think this solution should work but I don't like it and there are maybe better way to solve your problem :
sorted_players = [[]]
arr.each do |arr_fid|
sorted_players << players.collect{|player| player if player.include?(arr_fid)}
end
You have two options:
Use order to sort the results with the query
Use sort to sort the results in memory
You may use 1. It will be something like:
#plrdet = Player.find_all_by_fid(arr).order("address")

How do I iterate through a hash where I can view the next key also?

I have a hash of dates to money, and I need to put new money deposits inbetween a set of dates.
so, lets say my hash is
{"000000001" => "0.00", "000000002" ="12.34", "000000010" => "5.95"}
and I want to insert 000000008, 54.34 then my resulting hash should be
{"000000001" => "0.00", "000000002" ="66.68", "000000010" => "5.95"}
*(These are example time stamps)
so... I was thinking something like...
my_hash.each_with_index do |key_value, index|
if index == my_hash.length then return my_hash end
if time >= my_hash[dat[0]][0].to_i and time <= my_hash[dat[0]].next[0].to_i
my_hash[index][1] += value
end
end
end
which I know is invalid, but I need help. Thanks!
Use each_cons:
{
"000000001" => "0.00", "000000002" => "66.68", "000000010" => "5.95"
}.each_cons(2) do |(prev_key, prev_value), (next_key, next_value)|
p "#{prev_key} preceedes #{next_key}"
end
facets probably has something like what you proposed.
You can get the previous key like
previous = nil; a.each_key{|k| p 'key is', k, 'previous is', previous; previous = k}

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