Push a hash into an array in a loop rails - ruby-on-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?

Related

Array of hashes is overriding data directly to array

I want to make an array of hashes. But the problem is after first iteration when code goes to next line then it directly replaces the content of array.
#item_name =[]
item = {}
#invoiceinfo.each do |invoice|
item[:name] = Invoiceinfo.find(#invoiceinfo.id).item.name
item[:desc] = Invoiceinfo.find(#invoiceinfo.id).desc
item[:unit_price] = Invoiceinfo.find(#invoiceinfo.id).unit_price
byebug
#item_name.push (item)
end
This is what i am getting
after first iteration suppose i have this data
#item_name = [{:name=>"usman", :desc=>"sample ", :unit_price=>100}]
As soon as next line is executed it directly changes #item_name(name variable)
After executing item[:name] = Invoiceinfo.find(#invoiceinfo.id).item.name
the content of the #item_name is changed
#item_name = [{:name=>"next_name", :desc=>"sample ", :unit_price=>100}]
Any help would be appreciated.
Thannks
Try something like this
#item_name = []
#invoiceinfo.each do |invoice|
invoice_info = Invoiceinfo.find(#invoiceinfo.id)
item = {}
item[:name] = invoice_info.item.name
item[:desc] = invoice_info.desc
item[:unit_price] = invoice_info.unit_price
#item_name.push(item)
end
If you consider using ruby paradigms and best practices in ruby code, this mistake won’t happen in the future.
#item_name = #invoiceinfo.each_with_object([]) do |invoice, acc|
invoice_info = Invoiceinfo.find(#invoiceinfo.id)
acc.push(
name: invoice_info.item.name,
desc: invoice_info.desc
unit_price: invoice_info.unit_price
)
end

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

Getting the number of same elements in both arrays in Ruby

I need to count the number of values that both arrays have.
def process_2arrays(arr1, arr2)
length1 = arr1.count
length2 = arr2.count
arr3 = []
i = 0
while length1 >= i do
ci = arr1[i]
if arr2.include?(ci)
arr3 << ci
damn = arr3.count
i = i + 1
end
return [(damn), (2), (3), (4)]
end
end
When I pass the values to the function it returns [nil, 2, 3, 4]
Whats the problem here?
To find elements that exist in both arrays, use the set intersection method &.
http://ruby-doc.org/core-2.2.0/Array.html#method-i-26
def count_same_elements(a1,a2)
(array1 & array2).length
end
Example
count_same_elements([1,2,3,4],[2,3,4,5])
=> 3
damn is initialized within a do .. end block, specifically the while block. Therefore, its value will live within that scope, and when you call the variable outside the block its value is nil.
If you want to preserve the value, you must initialize the variable to nil outside the block.
i = 0
damn = nil
...
As a side note, your code is lacking the most basic Ruby standards. In Ruby you generally use an iterator, not the while. Moreover, you don't use the return at the end of a method.
This is how you would write your method in Ruby using the iterators and taking advantage of some methods from the core library.
def process_2arrays(arr1, arr2)
arr3 = arr1.select { |e| arr2.include?(e) }
[arr3.size, 2, 3, 4]
end
Changing completely approach, you can use
def process_2arrays(arr1, arr2)
(arr1 & arr2).size
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)

Ruby on rails save data inside loop

object.each do |info|
#user_work_history.fb_user_id = facebook_session.user.id
#user_work_history.city = info.location.city
#user_work_history.country = info.location.state
#user_work_history.company_name = info.company_name
#user_work_history.description = info.description
#user_work_history.start_date = info.start_date
#user_work_history.end_date = info.end_date
#user_work_history.position = info.position
#user_work_history.updated_at = Time.now
#user_work_history.save
end
here is the code but inside loop data is not saving only one record is saved.
I believe you have to add
#user_work_history = UserWorkHistory.new
to the first line inside the loop. (or whatever the model is)
When you do that kind of loop you need to change the reference to the instance variable #user_work_history. What your loop does is that for each iteration it updates the state of the same object!
What you should do, is to set the #user_work_history before each iteration, like this:
object.each do |info|
#user_work_history = UserWorkHistory.new(:fb_user_id => facebook_session.user.id) # for example
#user_work_history.city = info.location.city
#user_work_history.country = info.location.state
(...)
#user_work_history.save # here it saves new tuple
end

Resources