Convert array of Model into an array of the specified Model.attribute - ruby-on-rails

cars = Car.find(data).find_all{ |car| car.model == "Honda" }
this returns a list of Car's--I'd like to convert this list to a list that only contains the car.id's. How would I do it in a Ruby like way?

Simply call:
cars = Car.find(data).find_all{ |car| car.model == "Honda" }.map{ |car| car.id }
http://corelib.rubyonrails.org/classes/Array.html#M000427

You can do this:
car_ids = Car.find(data).find_all{ |car| car.model=="Honda" }.map{ |car| car.id }
Essentially, array.map { |x| f(x) } returns a new array of identical size, which contains the result of calling f on each of the original array's entries, in the same order.

I'd do it like that:
cars = Car.where(id: data, model: 'Honda').pluck(:id)
assuming that data is an array of car id's

Related

How to merge same hashes in array?

If I have:
array = [{:external_product_id=>"A", :quantity=>1}, {:external_product_id=>"A", :quantity=>2}, {:external_product_id=>"B", :quantity=>1}]
and want to transform it into:
array = [{:external_product_id=>"A", :quantity=>3}, {:external_product_id=>"B", :quantity=>1}]
i.e., merging products with the same id ("A") together. Is there any easier way to do this than using map, select, etc?
anything like this?
array.group_by { |item| item[:external_product_id] }
.map do |external_product_id, items|
{
external_product_id: external_product_id,
quantity: items.sum { |item| item[:quantity] }
}
end
=> [{:external_product_id=>"A", :quantity=>3}, {:external_product_id=>"B", :quantity=>1}]

Flatten array of nested hashes

I have an array of nested hashes that looks something like this:
[{"month"=>1,
"percentiles"=>{"25"=>768.06, "50"=>1868.5, "75"=>3043.79, "90"=>4161.6},
"total_revenue"=>1308620.0,
"year"=>2017},
{"month"=>2,
"percentiles"=>{"25"=>922.63, "50"=>2074.31, "75"=>3048.87, "90"=>4018.6},
"total_revenue"=>1105860.0,
"year"=>2017}]
That I would like to flatten into this:
[{"month"=>1,
"25"=>768.06, "50"=>1868.5, "75"=>3043.79, "90"=>4161.6,
"total_revenue"=>1308620.0,
"year"=>2017},
{"month"=>2,
"25"=>922.63, "50"=>2074.31, "75"=>3048.87, "90"=>4018.6,
"total_revenue"=>1105860.0,
"year"=>2017}]
I have been looking and testing different methods with no luck. Any ideas on how to accomplish this? The end goal is to mass update/insert these into a database, so if there is a better way to accomplish that, I would like to see a different approach.
If you don't mind modifying the array in-place then you could say:
array.each { |h| h.merge!(h.delete('percentiles')) }
If you're not sure that all the hashes have 'percentiles' keys then you could say:
# Explicitly check
array.each { |h| h.merge!(h.delete('percentiles')) if(h.has_key?('percentiles')) }
# Convert possible `nil`s to `{ }`
array.each { |h| h.merge!(h.delete('percentiles').to_h) }
# Filter before merging
array.select { |h| h.has_key?('percentiles') }.each { |h| h.merge!(h.delete('percentiles')) }
If you want to flatten all hash values then you can do things like this:
array.each do |h|
h.keys.each do |k|
if(h[k].is_a?(Hash))
h.merge!(h.delete(k))
end
end
end
If you don't want to modify the hashes inside the array then variations on:
flat = array.map(&:dup).each { |h| h.merge!(h.delete('percentiles')) }
flat = array.map do |e|
e.each_with_object({}) do |(k, v), h|
if(v.is_a?(Hash))
h.merge!(v)
else
h[k] = v
end
end
end

Ruby on rails How to find first item in array that matches items in another array

I have a leaderboard array that looks something like this:
[{:member=>"1", :score=>7.0, :rank=>1}, {:member=>"5", :score=>6.0, :rank=>2}, {:member=>"4", :score=>5.0, :rank=>3}, {:member=>"3", :score=>4.0, :rank=>4}, {:member=>"2", :score=>3.0, :rank=>5}]
I also have an array of active user ids [3,5].
How can I get the member number of the highest ranked active user and assign that to a variable? The leaderboard array will always be in order of rank.
One method would be to reduce your array to only entries who's :member is also in the active user IDs array, and then take the first element of that array:
leaderboard = [...]
active_user_ids = [3,5]
leaderboard.take_while{ |m| active_user_ids.include?(m[:member].to_i) }.first
leaderboard = [{:member=>"1", :score=>7.0, :rank=>1},
{:member=>"5", :score=>6.0, :rank=>2},
{:member=>"4", :score=>5.0, :rank=>3},
{:member=>"3", :score=>4.0, :rank=>4},
{:member=>"2", :score=>3.0, :rank=>5}]
active_members = [3,5]
highest_ranked_active_member = leaderboard.
select { |h| active_members.include? h[:member].to_i }.
min_by { |h| h[:rank] }[:member]
#=> "5"
This is a case where I love creating reusable lambdas to reuse code when querying the data.
active_members = [3,5]
active_member = -> member { active_members.include? member[:member].to_i }
member_score = -> member { member[:score] }
leader_board = ...
# Find first active_member:
p leader_board.find(&active_member) #=> {:member=>"5", :score=>6.0, :rank=>2}
# Find active member with lowest and highest score:
p leader_board.select(&active_member).minmax_by(&member_score) #=> [{:member=>"3", :score=>4.0, :rank=>4}, {:member=>"5", :score=>6.0, :rank=>2}]
list = [
{:member=>"1", :score=>7.0, :rank=>1},
{:member=>"5", :score=>6.0, :rank=>2},
{:member=>"4", :score=>5.0, :rank=>3},
{:member=>"3", :score=>4.0, :rank=>4},
{:member=>"2", :score=>3.0, :rank=>5}
]
list.select { |item| [3,5].include? item[:member].to_i }.max { |item| item[:rank] }[:member] => "3"

Call the same function on a list and return a list with no duplicates?

I have this function:
medIntCategory = MedicalInterventionCategory.find_by_category_text(category.category.text)
However now I have a list of categories called categories.
I would like to execute the above code for each category and get back a list of medIntCategories, but with no duplicates.
Is there a simple way to do this since I am only dealing with integers?
in simple terms:
categoryList = []
for each category in categories do
categoryList += MedicalInterventionCategory.find_by_category_text(category.category.text)
end
But with duplicate checking
This sounds like a job for Array#map and Array#uniq:
category_list = categories.map{|category|
MedicalInterventionCategory.find_by_category_text(category.category.text)
}.uniq
#result=Array.new
##assuming that it returns an array
medIntCategory = MedicalInterventionCategory.find_by_category_text(category.category.text)
##get the first category obtained
#result << medIntCategory
if medIntCategory.present?
medIntCategory.each do |m|
##add in same array only if not present
if !#result.include?(m)
#result << m.find_by_category_text(c.category.text)
end
end
##return a unique value array
#result.flatten.compact.uniq unless #result.blank?
end
HOPE IT HELPS
I think this would work
category_list = []
categories.each do |category|
category_list << MedicalInterventionCategory.find_by_category_text(category.category.text).distinct
end

Rails array sort

I have in rails this array:
#array = [{'82'=>'1'}, {'81'=>'0'},{'32'=>'12'}]
How can I sort it to have that result? I want to have this:
#array = [{'32'=>'12'}, {'82'=>'1'},{'81'=>'0'}]
and next - how then I can get #array[0] hash key (32)
This is an array of hash where hash is {'user_id'=>'counter'}
This will sort the array by value, in descending order, in place:
array.sort! { |h1, h2| h2.values.first <=> h1.values.first }
It can also be done with sort_by! followed by reverse!.
array.sort_by! { |h| h.values } .reverse!
Then, these will get you the first value and first key, respectively:
array.first.values.first
array.first.keys.first
Just append keys.sort to the end of the array. Use #array.keys.sort
#array.sort { |x,y| x.keys.first <=> y.keys.first }
Try using Enumerable#sort_by, and Array#reverse! to change the order.
> #array.sort_by { |h| h.values.first }.reverse!
=> [{"32"=>"12"}, {"82"=>"1"}, {"81"=>"0"}]

Resources