Ruby - iterating through database results and storing them in a hash - ruby

Consider the following:
details = Hash.new
# Example of this Hash's final look
details["team1"] = "Example"
details["team2"] = "Another team"
details["foo"] = "Bar"
The way I get the names of the two teams is through:
teams = Match.find(1).teams
=> [#<Team id: 1, name: "England">, #<Team id: 2, name: "Australia">]
Now I would like to save the names of the teams into the Hash under team1 and team2. If I were using arrays I could do:
teams.each do |team|
details << team.name
end
However, I need to do this with the Hash I have shown above. How would one go about accomplishing this?

Hash[teams.map { |x| ["team_#{x.id}", x.name] }]
# => {"team_1"=>"England", "team_2"=>"Australia"}
If you want to keep id 1 and 2
Hash[a.map.with_index { |x,i| ["team_#{i.succ}", x.name] }]
# => {"team_1"=>"England", "team_2"=>"Australia"}

What about this?
teams.each_with_index do |team, idx|
id = "team#{idx + 1}"
details[id] = team.name
end
Here you take the team object and make hash key out of it, and then use that key to set a value.

How about using an inject for a one liner?
teams.inject({}){ |details, team| details["team#{team.id}"] = team.name; details }
The return value will be an Array or Hashes.

{}.tap do |h|
Match.find(1).teams.each_with_index {|t, i| h["team#{i+1}"] = t.name}
end

Related

Looping an array and storing the values to a hash in ruby

I am trying to loop an array which might look like following:
names = ['sid','john'] #this array will be dynamic, The values keep changing
I am trying to write a method where I will define an empty hash and loop the array using .each
and then store the values to hash.But not working.
def add_address
names = ['sid','john']
addr_arr = {}
names.each do |n|
addr_arr['name'] = n
end
addr_arr
end
this returns only {"name"=>"john"}.
What am I doing wrong?
The problem with your implementation is that there's only one hash and each time you set a value for the "name" key, the previous value for that key will be deleted and replaced by the new value.
I see addr_arr has arr in the name, so I assume you wanted something like this:
def add_address
names = ['sid','john']
addr_arr = []
names.each do |n|
addr_arr << { "name" => n}
end
addr_arr
end
add_address
#=> [{"name"=>"sid"}, {"name"=>"john"}]
or shorter:
['sid','john'].map{ |name| {"name" => name} }
#=> [{"name"=>"sid"}, {"name"=>"john"}]
If you always use the key 'name', you're overwriting its values every time, I don't think that's what you want. I don't know if this is what you want anyway, but this should be enough to understand the problem
names.each do |n|
addr_arr[n] = n
end

How do you check for matching keys in a ruby hash?

I'm learning coding, and one of the assignments is to return keys is return the names of people who like the same TV show.
I have managed to get it working and to pass TDD, but I'm wondering if I've taken the 'long way around' and that maybe there is a simpler solution?
Here is the setup and test:
class TestFriends < MiniTest::Test
def setup
#person1 = {
name: "Rick",
age: 12,
monies: 1,
friends: ["Jay","Keith","Dave", "Val"],
favourites: {
tv_show: "Friends",
things_to_eat: ["charcuterie"]
}
}
#person2 = {
name: "Jay",
age: 15,
monies: 2,
friends: ["Keith"],
favourites: {
tv_show: "Friends",
things_to_eat: ["soup","bread"]
}
}
#person3 = {
name: "Val",
age: 18,
monies: 20,
friends: ["Rick", "Jay"],
favourites: {
tv_show: "Pokemon",
things_to_eat: ["ratatouille", "stew"]
}
}
#people = [#person1, #person2, #person3]
end
def test_shared_tv_shows
expected = ["Rick", "Jay"]
actual = tv_show(#people)
assert_equal(expected, actual)
end
end
And here is the solution that I found:
def tv_show(people_list)
tv_friends = {}
for person in people_list
if tv_friends.key?(person[:favourites][:tv_show]) == false
tv_friends[person[:favourites][:tv_show]] = [person[:name]]
else
tv_friends[person[:favourites][:tv_show]] << person[:name]
end
end
for array in tv_friends.values()
if array.length() > 1
return array
end
end
end
It passes, but is there a better way of doing this?
I think you could replace those for loops with the Array#each. But in your case, as you're creating a hash with the values in people_list, then you could use the Enumerable#each_with_object assigning a new Hash as its object argument, this way you have your own person hash from the people_list and also a new "empty" hash to start filling as you need.
To check if your inner hash has a key with the value person[:favourites][:tv_show] you can check for its value just as a boolean one, the comparison with false can be skipped, the value will be evaluated as false or true by your if statement.
You can create the variables tv_show and name to reduce a little bit the code, and then over your tv_friends hash to select among its values the one that has a length greater than 1. As this will give you an array inside an array you can get from this the first element with first (or [0]).
def tv_show(people_list)
tv_friends = people_list.each_with_object(Hash.new({})) do |person, hash|
tv_show = person[:favourites][:tv_show]
name = person[:name]
hash.key?(tv_show) ? hash[tv_show] << name : hash[tv_show] = [name]
end
tv_friends.values.select { |value| value.length > 1 }.first
end
Also you can omit parentheses when the method call doesn't have arguments.

New hash from existing hash within list - Ruby

I have a list that contains hashes that looks similar to this:
list = [{"created_at"=>"2016-11-07T18:49:51.000Z",
"updated_at"=>"2016-11-07T18:49:51.000Z",
"id"=>1,
"name"=>"Test1",
"title"=>"Test1",
"description"=>""},
{"created_at"=>"2017-05-24T13:34:13.000Z",
"updated_at"=>"2017-05-24T13:34:13.000Z",
"id"=>23,
"name"=>"Test2",
"title"=>"Test2",
"description"=>nil}]
I want to be able to iterate over this list of hashes and create a new hash that only has the id's value as a key, and the name's value as the value of the key. Currently my solution is this:
def new_hash(list)
#new_hash = Hash.new
list.each do | x |
#new_hash[x["id"]] = x["name"]
end
end
This produces a hash like this:
{1=>"Test1", 23=>"Test2"}
My question is, is there a more elegant way to approach this in Ruby?
Try this one
Hash[list.map { |h| h.values_at('id', 'name') }]
=> {1=>"Test1", 23=>"Test2"}
list.each_with_object({}) { |g,h| h[g["id"]] = g["name"] }
Another option:
list.map {|hash| [hash["id"], hash["name"]]}.to_h
#=> {1=>"Test1", 23=>"Test2"}
data = {name: 'akshay', last_name: 'kakade'}
new_hash = Hash[data]
data.object_id
new_hash.object_id

Get element of an array by its contents

I'm sorry for weird wording. I don't know what you call this. I have this array:
[#<Item:0x007faeea066508 #name="Backpack", #exam="Not much here... just a backpack">]
This is an inventory array. The user will type something like "examine backpack" and it will return the #exam of of the element. How would you get that element only knowing #name? Thanks!
This is what you have:
class Item
# accessors for #name and #exam possibly defined here
def initialize(name, exam)
#name = name
#exam = exam
end
# methods possibly defined here
end
item = Item.new("Backpack", "Just a backpack")
#=> #<Item:0x0000010201dda0 #name="Backpack", #exam="Just a backpack">
So you have an array a with one element, an instance of class Item with the instance variables #name and #exam having the values "Backpack" and "Just a backpack", respectively:
a = [item]
#=> [#<Item:0x0000010201dda0 #name="Backpack", #exam="Just a backpack">]
You can use Object#instance_variable_get to retrieve the values of the instance variables #name and #exam, which I will store in local variables name and exam:
name = a.first.instance_variable_get(:#name) #=> "Backpack"
exam = a.first.instance_variable_get(:#exam) #=> "Just a backpack"
Now that you have the values of those variables, you can do whatever you like with them.
You probably want to select using a block (assuming your Item class responds to .name and .exam:
items = [#<Item:0x007faeea066508 #name="Backpack", #exam="Not much here... just a backpack">]
item = items.select {|i| i.name =~ /backpack/i }
puts item.exam
Here is my code:
articles = ArticleType.all
My result:
[#<ArticleType id: 1, name: "News", slug: "news">, #<ArticleType id: 2, name: "Articles", slug: "articles">]
To get the name's value of the first element:
articles[0].name
=> "News"
To get the name's values of your array:
ArticleType.all.map(&:name)
To get the elements that contains 'N':
ArticleType.all.map { |x| puts x.name if x.name.include?('N') }
=> News
I hope it helps you!
You can do this as following:--
user_typed_string = "examine backpack"
items = [#<Item:0x007faeea066508 #name="Backpack", #exam="Not much here... just a backpack">]
item = items.select {|i| user_typed_string.include?(i.name) }.last
exam = item.exam unless item.nil?

grouping a hash based on parameters ruby

so i have the following
[{:item=>"x"}, {:item2=>"x"}, {:item3=>"x"}, {:item=>"x"},{:item3=>"x"}]
I want to get this split into groups,
so each group starts at item and ends at item3, item2 could be missing
ideally i want
{:item=>"x",:item2=>"x",:item3=>"x"} & {:item=>"x",:item3=>"x"}
So in a real example:
An 3 items need to be posted but I get an array from an excel spreadsheet
name: blah
id: blah
color: blah
name: blah
date: blah
size: blah
name: blah
id: blah
date: blah
color: blah
size: blah
I need to post each record, given I have an array like above is there some way to group/split the array on a given hash element key field?
If your data is really delimited by double line break, you should take advantage by splitting first by paragraph, then by line, then by the colon. Then you don't have to worry about missing data and can blindly fill in key/value pairs.
A functional approach, get the indexes where the :items are and split there:
hs = [{:item=>"x"}, {:item2=>"x"}, {:item3=>"x"}, {:item=>"x"},{:item3=>"x"}]
indexes = hs.map.with_index { |h, i| i if h.first[0] == :item }.compact
(indexes + [hs.size]).each_cons(2).map { |from, to| hs[from...to].reduce(:merge) }
#=> [{:item=>"x", :item2=>"x", :item3=>"x"}, {:item=>"x", :item3=>"x"}]
If you prefer a more declarative approach (I do), add some abstractions to your extensions library so you can write:
indexes = hashes.find_indexes { |h| h.first[0] == :item }
hashes.split_at(*indexes.drop(1)).map { |hs| hs.reduce(:merge) }
try this
input = [{:item=>"x"}, {:item2=>"x"}, {:item3=>"x"}, {:item=>"x"},{:item3=>"x"}]
res = []
input.each do |element|
if element.keys.first == :item
res << element
else
res.last.merge! element
end
end
puts puts res.inspect # => [{:item=>"x", :item2=>"x", :item3=>"x"}, {:item=>"x", :item3=>"x"}]
Pure awesomness of Ruby:
arr = [{:item=>"x"}, {:item2=>"x"}, {:item3=>"x"}, {:item=>"x"}, {:item3=>"x"}]
arr.each_slice(3).map { |a| a.inject(&:merge) }
=> [{:item=>"x", :item2=>"x", :item3=>"x"}, {:item=>"x", :item3=>"x"}]

Resources