matching array items in rails - ruby

I have two arrays and I want to see the total number of matches, between the arrays individual items that their are.
For example arrays with:
1 -- House, Dog, Cat, Car
2 -- Cat, Book, Box, Car
Would return 2.
Any ideas? Thanks!
EDIT/
Basically I have two forms (for two different types of users) that uses nested attributes to store the number of skills they have. I can print out the skills via
current_user.skills.each do |skill| skill.name
other_user.skills.each do |skill| skill.name
When I print out the array, I get: #<Skill:0x1037e4948>#<Skill:0x1037e2800>#<Skill:0x1037e21e8>#<Skill:0x1037e1090>#<Skill:0x1037e0848>
So, yes, I want to compare the two users skills and return the number that match. Thanks for your help.

This works:
a = %w{house dog cat car}
b = %w{cat book box car}
(a & b).size
Documentation: http://www.ruby-doc.org/core/classes/Array.html#M000274
To convert classes to an array using the name, try something like:
class X
def name
"name"
end
end
a = [X.new]
b = [X.new]
(a.map{|x| x.name} & b.map{|x| x.name}).size
In your example, a is current_user.skills and b is other_users.skills. x is simply a reference to the current index of the array as the map action loops through the array. The action is documented in the link I provided.

Related

How to implement semi-random groups with Ruby?

suppose I've got groups:
{1=>[1,1,1,1,1,1], 2=>[2,2,2], 3=>[3,3,3,3,3,3], 4=>[4,4,4,4,4,4]}
the keys represent teams, and the values within the arrays represent employees. Imagine I wish to match employees in a semi-random way. I want to make groups of 3's-5's like this:
[1,1,2,3,5], [1,2,3,4], [1,2,3,3], [1,3,4,1,4]
I have the wish to create groups and have a bias for matching team members of opposite teams, but not an absolute bias. Also you must match every member of each team with a group.
How would you solve this?
This is how I've done it:
group_by_team = records.group_by {|x| x.team_id}.values
mixed_groups = group_by_team.each{|x| x.shuffle!}
# take 1 element from each team and mix
# the number of teams is defined as a constant so we don't have to hit the db with a count
for index in (1..(TEAMS-1))
zipped_groups ||= mixed_groups[0]
zipped_groups = zipped_groups.zip(mixed_groups[index])
end
# flatten the arrays to produce one large Array
# remove nil values from ziped steps with compact!
zipped_groups = zipped_groups.flatten!.compact!
lunch_groups = zipped_groups.each_slice(3)
# we can no longer reduce table size, so lets join two small lunch groups
if lunch_groups.any?{|x| x.size<3}
lunch_groups = self.merge_last_two(lunch_groups)
end
But the problems with my implementation are vast. Groups size is fixed at 3. And its no exactly elegant, or efficient.
How would you make semi-random groups happen?

Ruby 2D Extracting Information

I am relatively new to coding and am learning ruby right now. I came across a problem where I have a huge data record (>100k record) consisting of unique ID and another consisting of the date of birth. So it's basically a 2D array. How do I go about creating a method such that every time when I key in method(year), it will give me all the unique ID of those born in the year i choose? And how do I loop this?
The method I tried doing is as follow:
def Id_with_year(year)
emPloyee_ID_for_searching_year = [ ]
employeelist.sort_by!{|a,b|b}
if employeelist.select{|a,b| b == year}.map{|a,b| a}
return emPloyee_ID_for_searching_year
end
end
I should point out that the ID are sorted. That's why I am trying to sort the year in this method so that it will give me all the ID for the year I key in. The output I had was that it returned me [ ] with nothing inside instead of the ID.
Sidenote: methods in ruby are to be named in snake case (this is not mandatory, though.)
The problem you experience is you return what was never changed. The below should work:
def id_with_year(year)
employeelist.sort_by(&:last) # sorting by last element of array
.select{|_,b| b == year} # select
.map(&:first) # map to the first element
end

Understanding hashes

An exercise says:
Create three hashes called person1, person2, and person3, with first
and last names under the keys :first and :last. Then create a params
hash so that params[:father] is person1, params[:mother] is person2,
and params[:child] is person3. Verify that, for example,
params[:father][:first] has the right value.
I did
person1 = {first: "Thom", last: "Bekker"}
person2 = {first: "Kathy", last: "Bekker"}
person2 = {first: "Anessa", last: "Bekker"}
then the params hash in Rails
params = {}
params[:father] = person1
params[:mother] = person2
params[:child] = person3
Now I can ask for father, mother or child's first or last name like so
params[:father][:first] gives me "Thom".
What makes params[:father][:first][:last] return an error? Is there a way to make that return "Thom Bekker"?
I have no way to check if the way I came up with is correct, is there a better way to do the exercise?
Is there a reason why symbol: is better than symbol =>?
Your Return Value is a Single Hash Object
You're misunderstanding the type of object you're getting back. params[:father] returns a single Hash object, not an Array or an Array of hashes. For example:
params[:father]
#=> {:first=>"Thom", :last=>"Bekker"}
params[:father].class
#=> Hash
So, you can't access the missing third element (e.g. :last) because there's no such element within the value of params[:father][:first].
Instead, you could deconstruct the Hash:
first, last = params[:father].values
#=> ["Thom", "Bekker"]
or do something more esoteric like:
p params[:father].values.join " "
#=> "Thom Bekker"
The point is that you have to access the values of the Hash, or convert it to an Array first, rather than treating it directly like an Array and trying to index into multiple values at once.
In Ruby, using square brackets on the Hash or other classes is actually using a method available for an object of that class (this one). When you call these methods in your example, each of these methods will be called and will return its result before the next method is called. So, as you've defined it:
Calling [:father] on params returns the hash represented by person1
[:first] is then called on {first: "Thom", last: "Bekker"}, returning the corresponding value in the hash, "Thom"
[:last] is called on "Thom", which results in an error. Calling square brackets on a string with an integer between them can access the character in a string at that index (person1[:first][0] returns "T"), but "Thom" doesn't have a way of handling the :last symbol inside the square brackets.
There are a number of ways you could get the names printed as you wanted, one of the simplest being combining the string values in person1:
params[:father][:first] + " " + params[:father][:last]
returns "Thom Bekker"
So here's my question, what exactly makes params[:father][:first][:last] return an error? Is there a way to make that return "Thom Bekker"?
Both of these would work
params[:father][:first] + params[:father][:last]
params[:father].values.join(' ')
But maybe it would be better to think about them like the nested structures that they are:
father = params[:father]
name = father[:first] + father[:last]
puts name
To answer your last question, pretend that there's no difference between a hashrocket => and symbol:. This is one where you don't need to care for a long time. Maybe around year 2 start asking this again, but for learning treat them as if they were equivalent.
(Full disclosure, there are differences, but this is a holy war that you really don't want to see played out)

removing duplicates from list of strings (output from Twilio call - Ruby)

I'm trying to display total calls from a twilio object as well as unique calls.
The total calls is simple enough:
# set up a client to talk to the Twilio REST API
#sub_account_client = Twilio::REST::Client.new(#account_sid, #auth_token)
#subaccount = #sub_account_client.account
#calls = #subaccount.calls
#total_calls = #calls.list.count
However, I'm really struggling to figure out how to display unique calls (people sometimes call back form the same number and I only want to count calls from the same number once). I'm thinking this is a pretty simple method or two but I've burnt quite a few hours trying to figure it out (still a ruby noob).
Currently I've been working it in the console as follows:
#sub_account_client = Twilio::REST::Client.new(#account_sid, #auth_token)
#subaccount = #sub_account_client.account
#subaccount.calls.list({})each do |call|
#"from" returns the phone number that called
print call.from
end
This returns the following strings:
+13304833615+13304833615+13304833615+13304833615+13304567890+13304833615+13304833615+13304833615
There are only two unique numbers there so I'd like to be able to return '2' for this.
Calling class on that output shows strings. I've used "insert" to add a space then have done a split(" ") to turn them into arrays but the output is the following:
[+13304833615][+13304833615][+13304833615][+13304833615][+13304567890][+13304833615][+13304833615][+13304833615]
I can't call 'uniq' on that and I've tried to 'flatten' as well.
Please enlighten me! Thanks!
If what you have is a string that you want to manipulate the below works:
%{+13304833615+13304833615+13304833615+13304833615+13304567890+13304833615+13304833615+13304833615}.split("+").uniq.reject { |x| x.empty? }.count
=> 2
However this is more ideal:
#subaccount.calls.list({}).map(&:from).uniq.count
Can you build an array directly instead of converting it into a string first? Try something like this perhaps?
#calllist = []
#subaccount.calls.list({})each do |call|
#"from" returns the phone number that called
#calllist.push call.from
end
you should then be able to call uniq on #calllist to shorten it to the unique members.
Edit: What type of object is #subaccount.calls.list anyway?
uniq should work for creating a unique list of strings. I think you may be getting confused by other non-related things. You don't want .split, that's for turning a single string into an array of word strings (default splits by spaces). Which has turned each single number string, into an array containing only that number. You may also have been confused by performing your each call in the irb console, which will return the full array iterated on, even if your inner loop did the right thing. Try the following:
unique_numbers = #subaccount.calls.list({}).map {|call| call.from }.uniq
puts unique_numbers.inspect

How do I find a integer/max integer in an array for ruby and return the indexed position?

This is what I have so far
ages = [20,19,21,17,31,33,34]
names = [Bob, Bill, Jill, Aimee, Joe, Matt, Chris]
How do I take ages and apply a method to it to extract the largest integer out of it and learn its indexed position. The reason being I want to know which person in names is the oldest. Parallel assignment is blocking my ability to do a .sort on the array becasue it changes the position of element associted with names.
Please include code to mull over thanks,
ages.zip(names).max
names[ages.index(ages.max)]
What it does is find the maximum value in ages (ages.max), get the index of the first matching value in ages, and use it to get the corresponding person. Note that if two or more people have the same age which is the maximum, it'll only give you the name of the first one in the array.
Edit: To address your comment, I'm not sure why you need this parallel arrays structure (it'd be much easier if you just had a person object). Nevertheless, you can try something like:
indices = []
ages.each_with_index { |age, i| indices << i if age < 20 }
indices.each { |i| puts names[i] }

Resources