How to save multiple initialized record with one save - ruby-on-rails

Take it as example.
new_array = []
Country.all do |c|
g = c
c = c.clone
c.country_name = "kkk"
new_array << c
end
At this point my new_array containing multiple records ..
How may i store all the values with one save or create ?
Any other better way ?

Related

Secure random unique number in loop

I have a loop that adds numbers in groups of a certain number which can be inputted by the user.
no_reps = #trial.number_of_repetitions
I'm looking to input a random number between one and the no_reps variable in groups of no_reps variable.
Current the r.treatment_index = SecureRandom.random_number(1..no_reps) isn't putting in unique numbers. The values match the range, but aren't unique per in_groups_of.
#trial.repetitions.in_groups_of(no_reps).each_with_index do |a, i|
a.each do |r|
r.repetition_index = i + 1
r.treatment_index = SecureRandom.random_number(1..no_reps)
end
end
Try to #shuffle prepopulated array:
#trial.repetitions.in_groups_of(no_reps).each_with_index do |a, i|
treatment_indexes = (1..no_reps).to_a.shuffle
a.each_with_index do |r, j|
r.repetition_index = i + 1
r.treatment_index = treatment_indexes[j]
end
end
UPD: If you take care about speed:
treatment_indexes = (1..no_reps).to_a
#trial.repetitions.in_groups_of(no_reps).each_with_index do |a, i|
treatment_indexes.shuffle!
...

How to loop through arrays of different length in Ruby?

Let's say i have two relation arrays of a user's daily buy and sell.
how do i iterate through both of them using .each and still let the the longer array run independently once the shorter one is exhaused. Below i want to find the ratio of someone's daily buys and sells. But can't get the ratio because it's always 1 as i'm iterating through the longer array once for each item of the shorter array.
users = User.all
ratios = Hash.new
users.each do |user|
if user.buys.count > 0 && user.sells.count > 0
ratios[user.name] = Hash.new
buy_array = []
sell_array = []
date = ""
daily_buy = user.buys.group_by(&:created_at)
daily_sell = user.sells.group_by(&:created_at)
daily_buy.each do |buy|
daily_sell.each do |sell|
if buy[0].to_date == sell[0].to_date
date = buy[0].to_date
buy_array << buy[1]
sell_array << sell[1]
end
end
end
ratio_hash[user.name][date] = (buy_array.length.round(2)/sell_array.length)
end
end
Thanks!
You could concat both arrays and get rid of duplicated elements by doing:
(a_array + b_array).uniq.each do |num|
# code goes here
end
Uniq method API
daily_buy = user.buys.group_by(&:created_at)
daily_sell = user.sells.group_by(&:created_at
buys_and_sells = daily_buy + daily_sell
totals = buys_and_sells.inject({}) do |hsh, transaction|
hsh['buys'] ||= 0;
hsh['sells'] ||= 0;
hsh['buys'] += 1 if transaction.is_a?(Buy)
hsh['sells'] += 1 if transaction.is_a?(Sell)
hsh
end
hsh['buys']/hsh['sells']
I think the above might do it...rather than collecting each thing in to separate arrays, concat them together, then run through each item in the combined array, increasing the count in the appropriate key of the hash returned by the inject.
In this case you can't loop them with each use for loop
this code will give you a hint
ar = [1,2,3,4,5]
br = [1,2,3]
array_l = (ar.length > br.length) ? ar.length : br.length
for i in 0..array_l
if ar[i] and br[i]
puts ar[i].to_s + " " + br[i].to_s
elsif ar[i]
puts ar[i].to_s
elsif br[i]
puts br[i].to_s
end
end

ruby - writing an array to a hash without overwriting

I do the following
my_hash = Hash.new
my_hash[:children] = Array.new
I then have a function that calls itself a number of time each time writing to children
my_hash[:children] = my_replicating_function(some_values)
How do I write without overwriting data that is already written ?
This is what the entire function looks like
def self.build_structure(candidates, reports_id)
structure = Array.new
candidates.each do |candidate, index|
if candidate.reports_to == reports_id
structure = candidate
structure[:children] = Array.new
structure[:children] = build_structure(candidates, candidate.candidate_id)
end
end
structure
end
Maybe this:
structure[:children] << build_structure(candidates, candidate.candidate_id)
structure[:children] << build_structure(candidates, candidate.candidate_id)

Push a hash into an array in a loop rails

I am trying to add hashes to an array whilst iterating through an each loop. Here's my controller code: the line I'm struggling with is setting the #royaltiesbychannel variable in the each loop:
def royalty(isbn)
sales_hash_by_channel = Sale.find_all_by_isbn_id(#isbn).group_by(&:channel_id)
sales_hash_by_channel.each do |ch_id, sale_array|
#royaltiesbychannel = Array.new()
value_total_by_channel = sale_array.sum(&:value)
quantity_total_by_channel = sale_array.sum(&:quantity)
#isbn.rules.each do |rule|
next unless rule.channel_id == ch_id
case quantity_total_by_channel
when 0..5000
#royaltiesbychannel = #royaltiesbychannel << {ch_id => value_total_by_channel * 0.5}
# (some other case-when statements)
end
end
end
In the console, when I set the ch_id and the value to something new and push the new values into the array:
#royaltiesbychannel = #royaltiesbychannel << {ch_id => value_total_by_channel * 0.5}
I get a nice array of hashes:
[{1=>100000.0}, {2=>3000.0}]
However, when I do #royaltiesbychannel.inspect in the view, I get just one key-value pair:
[{2=>3000.0}]
For ref:
#royaltiesbychannel.class = Array
#royaltiesbychannel.class = 1
#sales_hash_by_channel.class = Hash
#sales_hash_by_channel.size = 2
#isbn.rules.size = 4
So it looks like the push into the array is overwriting rather than adding. What am I doing wrong? Have I completely missed the point on how loops and .push work? Many thanks in advance.
You are initializing the array within the loop:
#royaltiesbychannel = Array.new()
It is being re-initialized each time, therefore you get only one result. Move it outside the each loop.
Your #royaltiesbychannel initialization is inside the first loop, so every time it starts that loop again it empties the array. Move it outside the loop and you should get the result you want.
def royalty(isbn)
#royaltiesbychannel = Array.new()
sales_hash_by_channel = Sale.find_all_by_isbn_id(#isbn).group_by(&:channel_id)
sales_hash_by_channel.each do |ch_id, sale_array|
value_total_by_channel = sale_array.sum(&:value)
quantity_total_by_channel = sale_array.sum(&:quantity)
#isbn.rules.each do |rule|
next unless rule.channel_id == ch_id
case quantity_total_by_channel
when 0..5000
#royaltiesbychannel = #royaltiesbychannel << {ch_id => value_total_by_channel * 0.5}
# (some other case-when statements)
end
end
end
You're setting #royaltiesbychannel to a new Array object during each iteration over sales_hash_by_channel should you be instead initialising it once outside of that loop instead?

ruby looping question

I want to make a loop on a variable that can be altered inside of the loop.
first_var.sort.each do |first_id, first_value|
second_var.sort.each do |second_id, second_value_value|
difference = first_value - second_value
if difference >= 0
second_var.delete(second_id)
else
second_var[second_id] += first_value
if second_var[second_id] == 0
second_var.delete(second_id)
end
first_var.delete(first_id)
end
end
end
The idea behind this code is that I want to use it for calculating how much money a certain user is going to give some other user. Both of the variables contain hashes. The first_var is containing the users that will get money, and the second_var is containing the users that are going to pay. The loop is supposed to "fill up" a user that should get money, and when a user gets full, or a user is out of money, to just take it out of the loop, and continue filling up the rest of the users.
How do I do this, because this doesn't work?
Okay. What it looks like you have is two hashes, hence the "id, value" split.
If you are looping through arrays and you want to use the index of the array, you would want to use Array.each_index.
If you are looping through an Array of objects, and 'id' and 'value' are attributes, you only need to call some arbitrary block variable, not two.
Lets assume these are two hashes, H1 and H2, of equal length, with common keys. You want to do the following: if H1[key]value is > than H2[key]:value, remove key from H2, else, sum H1:value to H2:value and put the result in H2[key].
H1.each_key do |k|
if H1[k] > H2[k] then
H2.delete(k)
else
H2[k] = H2[k]+H1[k]
end
end
Assume you are looping through two arrays, and you want to sort them by value, and then if the value in A1[x] is greater than the value in A2[x], remove A2[x]. Else, sum A1[x] with A2[x].
b = a2.sort
a1.sort.each_index do |k|
if a1[k] > b[k]
b[k] = nil
else
b[k] = a1[k] + b[k]
end
end
a2 = b.compact
Based on the new info: you have a hash for payees and a hash for payers. Lets call them ees and ers just for convenience. The difficult part of this is that as you modify the ers hash, you might confuse the loop. One way to do this--poorly--is as follows.
e_keys = ees.keys
r_keys = ers.keys
e = 0
r = 0
until e == e_keys.length or r == r_keys.length
ees[e_keys[e]] = ees[e_keys[e]] + ers[r_keys[r]]
x = max_value - ees[e_keys[e]]
ers[r_keys[r]] = x >= 0 ? 0 : x.abs
ees[e_keys[e]] = [ees[e_keys[e]], max_value].min
if ers[r_keys[r]] == 0 then r+= 1 end
if ees[e_keys[e]] == max_value then e+=1 end
end
The reason I say that this is not a great solution is that I think there is a more "ruby" way to do this, but I'm not sure what it is. This does avoid any problems that modifying the hash you are iterating through might cause, however.
Do you mean?
some_value = 5
arrarr = [[],[1,2,5],[5,3],[2,5,7],[5,6,2,5]]
arrarr.each do |a|
a.delete(some_value)
end
arrarr now has the value [[], [1, 2], [3], [2, 7], [6, 2]]
I think you can sort of alter a variable inside such a loop but I would highly recommend against it. I'm guessing it's undefined behaviour.
here is what happened when I tried it
a.each do |x|
p x
a = []
end
prints
1
2
3
4
5
and a is [] at the end
while
a.each do |x|
p x
a = []
end
prints nothing
and a is [] at the end
If you can I'd try using
each/map/filter/select.ect. otherwise make a new array and looping through list a normally.
Or loop over numbers from x to y
1.upto(5).each do |n|
do_stuff_with(arr[n])
end
Assuming:
some_var = [1,2,3,4]
delete_if sounds like a viable candidate for this:
some_var.delete_if { |a| a == 1 }
p some_var
=> [2,3,4]

Resources