Intersect array of hashes with array of ids - ruby-on-rails

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?}

Related

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.

How to combine one-dimensional ruby arrays into a two-dimensional array?

I have two arrays:
array of school names
array of school slugs
Say the array of school names is: [name1, name2, name3] and of slug names are: [slug1, slug2, slug3].
In ruby, how would I make an array [[name1, slug1], [name2, slug2], [name3, slug3]].
My attempt at the matter is kind of javascript-ish:
<% var schoolSelect = [];
for (var i=0; i<#schools.length; i++)
schoolSelect[i] = [#schools.pluck(:name)[i], #schools.pluck(:slug)[i]]; %>
You will be using Array#zip for it like:
names = %w(name1 name2 name3)
slugs = %w(slug1 slug2 slug3)
names.zip(slugs)
# [["name1", "slug1"], ["name2", "slug2"], ["name3", "slug3"]]
Suggest you consider a Hash for that data structure
schools = ["first", "second", "third"]
slugs = ["a", "b", "c"]
school_slugs = {}
(0..2).each do |position|
school_slugs[schools[position]] = slugs[position]
end
# => 0..2
school_slugs
# => {"first" => "a", "second" => "b", "third" => "c"}
If you use Arup's approach you can also make that into a Hash, i.e.
[["name1", "slug1"], ["name2", "slug2"], ["name3", "slug3"]].to_h
# => {"name1"=>"slug1", "name2"=>"slug2", "name3"=>"slug3"}
names = %w(name1 name2 name3)
slugs = %w(slug1 slug2 slug3)
Whenever you have two arrays of the same size, as here,
names.zip(slugs)
#=> [["name1", "slug1"], ["name2", "slug2"], ["name3", "slug3"]]
and
[names, slugs].transpose
#=> [["name1", "slug1"], ["name2", "slug2"], ["name3", "slug3"]]
are interchangeable.

Ruby - how to replace key in a hash by a key from different one?

I have this hash:
CARS = {"Audi" => 0,
"BMW" => 1,
...}
And this output from ActiveRecord (#top_cars):
{1=>18, 0=>17, 3=>13, 5=>10, 2=>5, 4=>1}
How do I replace the keys from #top_cars by the car names from CARS?
Thank you
EDIT:
So the desired output would be like {"BMW"=>18, "Audi"=>17, "Renault"=>13, "Mercedes"=>10, "Ford"=>5, "Porsche"=>1}
This would do the trick:
#top_cars.map {|key, value| [CARS.key(key), value]}.to_h
possible solution:
#top_cars.inject({}) {|memo, (key,value)| memo.merge(CARS.key(key) => value)}
You could merge cars with itself:
cars = { "Audi" => 0,
"Mercedes" => 1,
"Ford" => 2,
"Renault" => 3,
"BMW" => 4,
"Porsche" => 5
}
top_cars = {1=>18, 0=>17, 3=>13, 5=>10, 2=>5, 4=>1}
cars.merge(cars) { |*,n| top_cars[n] }
#=> {"Audi"=>17, "Mercedes"=>18, "Ford"=>5, "Renault"=>13, "BMW"=>1, "Porsche"=>10}
This uses the form of Hash#merge where a block is employed to determine the values of keys that are present in both hashes being merged, which here is all the keys.

Take array and convert to a hash Ruby

I am trying this for the first time and am not sure I have quite achieved what i want to. I am pulling in data via a screen scrape as arrays and want to put them into a hash.
I have a model with columns :home_team and :away_team and would like to post the data captured via the screen scrape to these
I was hoping someone could quickly run this in a rb file
require 'open-uri'
require 'nokogiri'
FIXTURE_URL = "http://www.bbc.co.uk/sport/football/premier-league/fixtures"
doc = Nokogiri::HTML(open(FIXTURE_URL))
home_team = doc.css(".team-home.teams").map {|team| team.text.strip}
away_team = doc.css(".team-away.teams").map {|team| team.text.strip}
team_clean = Hash[:home_team => home_team, :away_team => away_team]
puts team_clean.inspect
and advise if this is actually a hash as it seems to be an array as i cant see the hash name being outputted. i would of expected something like this
{"team_clean"=>[{:home_team => "Man Utd", "Chelsea", "Liverpool"},
{:away_team => "Swansea", "Cardiff"}]}
any help appreciated
You actually get a Hash back. But it looks different from the one you expected. You expect a Hash inside a Hash.
Some examples to clarify:
hash = {}
hash.class
=> Hash
hash = { home_team: [], away_team: [] }
hash.class
=> Hash
hash[:home_team].class
=> Array
hash = { hash: { home_team: [], away_team: [] } }
hash.class
=> Hash
hash[:hash].class
=> Hash
hash[:hash][:home_team].class
=> Array
The "Hash name" as you call it, is never "outputed". A Hash is basically a Array with a different index. To clarify this a bit:
hash = { 0 => "A", 1 => "B" }
array = ["A", "B"]
hash[0]
=> "A"
array[0]
=> "A"
hash[1]
=> "B"
array[1]
=> "B"
Basically with a Hash you additionally define, how and where to find the values by defining the key explicitly, while an array always stores it with a numerical index.
here is the solution
team_clean = Hash[:team_clean => [Hash[:home_team => home_team,:away_team => away_team]]]

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")

Resources