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
Related
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
I have a hash where the values are all arrays. I want to look up a key in this hash. If it exists I want to add a value to the array. If it does not exist (hash[key] returns nil) then I need to create the array and and add one value. Currently I have this:
hash[key].push elem unless hash[key].nul?
hash[key] ||= [elem]
This involves 3 lookups. I'm new to ruby so I'm sure there's a better way to do this. What is it?
My original plan was to make the default value for the hash [ ]. Then I can just use:
hash[key].push elem
Unfortunately if the key does not exist, that will only change the default value and not add a new key.
In this case you need to create a hash as below :
hash = Hash.new { |h,k| h[k] = [] }
The above is created to handle situations like your. Look new {|hash, key| block } → new_hash
hash = Hash.new { |h,k| h[k] = [] }
hash[:key1] << 1
hash[:key2] << 2
hash[:key1] << 3
hash # => {:key1=>[1, 3], :key2=>[2]}
You can try:
(hash[key] ||= []) << elem
However Arup's answer is much better.
You should create your hash with a default value.
hash = Hash.new { |h,k| h[k] = [] }
hash[key].push elem
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
Simplified version:
ar=['name: Joe', 'name: Jack', 'name: Jill']
hash={}
ar.each{|line| if line.include?('name'); hash['name'] = line;end;}
puts hash
My aim is to add all the elements in the array to the 'name'-key, but my code seeme to over-write the existing value.
Is'nt it possible to have multiple values assigned to one single key? I'd rather not use an array as value.
Edit:
I realized that my first example did'nt cover the whole problem:
extend the array to:
ar=['name: Joe', 'name: Jack', 'name: Jill', age: 29', 'age: 32', 'misc: Great weather']
What i'd is to have the 'name's grouped under the key 'name', and so on.
The number of attributes/keys is not known beforehand, so the arrays will have top be made dynamiclly.
There's no option besides using an array as a value. Otherwise how would you retrieve the multiple values? You'd need some kind of enumerable anyway, so there's no problem with using an array.
Try something like this:
hash = {}
ar = ['name: Joe', 'name: Jack', 'name: Jill']
hash['name'] = ar.select {|l| l.include? 'name'}.collect {|l| l.split.last}
hash # => {"name"=>["Joe", "Jack", "Jill"]}
Or, a little more simply:
hash = {"name" => ar.select {|l| l.include? 'name'}.collect {|l| l.split.last} }
For your edited question:
hash = Hash.new {|h,k| h[k] = [] }
ar.each {|l| k,v = l.split(": "); hash[k] << v }
hash # => {"name"=>["Joe", "Jack", "Jill"], "foo"=>["bar"]}
I have the following:
array_of_hashes = [{:a=>10, :b=>20}, {:a=>11, :b=>21}, {:a=>13, :b=>23}]
How would I go about finding if :a=>11 exists in array_of_hashes
array_of_hashes.include? does not seem to work
array_of_hashes.any? {|h| h[:a] == 11}
You did ask for a boolean result in the OQ, but if you really want the hash element itself do:
array_of_hashes.detect { |h| h[:a] == 11 }
If you want the result really fast you could group the original object and then get the result with a single hash lookup:
t = array_of_hashes.group_by { |x| x[:a] }
t[11]