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

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.

Related

Ruby - Create hash with keys and values as arrays

I am new to Ruby and trying to find if I can create a hash which has keys as keys_Array and values as val_array.
Currently I have the following but it gives empty array.
key_hash = Hash.new { |hash, key|
hash.key = ["#{csv['values']} #{csv['keys']}"]
}
p key_hash.keys #empty array here
If you're trying to create a hash from two corresponding arrays for keys and values, this is quick way:
keys = ["a", "b", "c"]
values = [1, 2, 3]
hash = Hash[keys.zip(values)]
# => {"a"=>1, "b"=>2, "c"=>3}
# for symbols
hash = Hash[keys.map(&:to_sym).zip(values)]
# => {:a=>1, :b=>2, :c=>3}
If you want to make a new hash from two hashes (one contains keys for new hash and other contains values with respect to keys in first hash then only)
you can use something like below :
keys = ['k1', 'k2', 'k3']
values = ['b1', 'b2']
h = {}
keys.zip(values) { |a,b| h[a.to_sym] = b }
# => nil
p h
# => {:k1=>"b1", :k2=>"b2", :k3=>nil}
Keep in mind that if the keys are more and values are less in number then key will have nil value as mentioned in the e.g. but if the keys are less as compare to values then it will now consider the remaining values for e.g.
keys =['b1', 'b2']
=> ["b1", "b2"]
values = ['k1', 'k2', 'k3']
=> ["k1", "k2", "k3"]
h = {}
=> {}
keys.zip(values) { |a,b| h[a.to_sym] = b }
=> nil
p h
{:b1=>"k1", :b2=>"k2"}

Needing to find matches in my controller from an array! Ruby on Rails

I am in a broken spot. I was able to get the array from into #set1 and now need to compare #set1 with #set2 and see how many matches there are. I can get the #array1 to work correctly if I have static numbers in an array in #array2 but not when I make it dynamic.
I need a way to compare these two arrays and am at a loss now!
def show
#set1 = Set1.find(params[:id])
#set2 = Set2.where(:date => #set1.date)
#array1 = [Set1.find(params[:id]).let1, Set1.find(params[:id]).let2]
#array2 = [Winnings.where(:date => #set1.date).let1, Winnings.where(:date => #set1.date).let2]
#intersection = #array1 & #array2
end
I think part of the problem here is that you can make new objects with the same attributes but that do not respond properly to the comparisons that the intersection operator :& uses.
Example:
class Thing
attr_reader :first,:last
def initialize(first,last)
#first = first
#last = last
end
end
thing1 = Thing.new("John","Smith")
thing2 = Thing.new("John","Smith")
thing1 == thing2
# => false
[thing1] & [thing2]
# => []
You might consider mapping each array to some identifying value (maybe id) and finding the intersection of those arrays. That is to say
#set1 = Set1.find(params[:id])
#set2 = Set2.where(:date => #set1.date)
#array1 = [Set1.find(params[:id]).let1, Set1.find(params[:id]).let2]
#array2 = [Winnings.where(:date => #set1.date).let1, Winnings.where(:date => #set1.date).let2]
#array1.map{|obj| obj.id} & #array2.map{|obj| obj.id}
# => an array of unique object ids that are in both #array1 and #array2
Or, if you want the objects themselves...
(#array1.map{|obj| obj.id} & #array2.map{|obj| obj.id}).map{ |id| Set.find(id) }

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]]]

Is there a method in Ruby that divides an array into two smaller arrays based on a logical condition?

Let's say I have a list of elements in an array, but there is a logical way to divide them into two groups. I want to put those elements into two smaller arrays based on that criteria. Here is some code that works and helps illustrate what I mean:
foo = ['a', 'bb', 'c', 'ddd', 'ee', 'f']
=> ["a", "bb", "c", "ddd", "ee", "f"]
a = foo.select{|element| element.length == 1}
=> ["a", "c", "f"]
b = foo.reject{|element| element.length == 1}
=> ["bb", "ddd", "ee"]
I seem to remember seeing some way by which a single method call would assign both a and b, but I don't remember what it was. It would look something like
matching, non_matching = foo.mystery_method{|element| element.length == 1}
Am I crazy, or does such a method exist in Ruby and/or Rails?
Yes! http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
matching, non_matching = foo.partition {|element| element.length == 1}

Intersect array of hashes with array of ids

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

Resources