In a book they showed me this declaration:
friends = [ { first_name: "Emily", last_name: "Laskin" }, { first_name: "Nick", last_name: "Mauro" }, { first_name: "Mark", last_name: "Maxwell" } ]
This doesn't look like a hash. And when I enter it in IRB i get an error.
What is this format?
It's an array of hashes, written in the Ruby 1.9 hash syntax.
{ first_name: "Emily", last_name: "Laskin" }
is equivalent to:
{ :first_name => "Emily", :last_name => "Laskin" }
The {key: value} syntax is new in 1.9 and is equivalent to {:key => value}.
It is an array of hashes, only the hashes are 1.9 style hashes.
Related
people = [
{id: 101, first_name: 'John', last_name: 'Doe'},
{id: 102, first_name: 'Tom', last_name: 'Rogers'},
{id: 103, first_name: 'Bill', last_name: ''}
]
I want to put a list of name like this
"John Doe, Tom Rogers, Bill"
How can i achieve this is in ruby?
Input
people = [
{ id: 101, first_name: 'John', last_name: 'Doe' },
{ id: 102, first_name: 'Tom', last_name: 'Rogers' },
{ id: 103, first_name: 'Bill', last_name: '' }
]
Code
p people.map { |x| x[:first_name].to_s + ' ' + x[:last_name].to_s }
.map(&:strip)
.join(",")
Output
"John Doe,Tom Rogers,Bill"
The other answers are good, but I wanted to add a demonstration of string interpolation.
people
.map { |p| "#{p[:first_name]} #{p[:last_name]}" }
.join(", ")
#rajagopalan has a good idea in using strip to remove unwanted whitespace at the beginning and end of the first and last name combination, but it might be even better to run this on each component of the name.
people
.map { |p| "#{p[:first_name].strip} #{p[:last_name].strip}" }
.join(", ")
I would do
people
.map { |p| p.values_at(:first_name, :last_name).join(' ').strip }
.join(', ')
#=> "John Doe, Tom Rogers, Bill"
or
people
.map { |p| "#{p[:first_name]} #{p[:last_name]}".strip }
.join(', ')
#=> "John Doe, Tom Rogers, Bill"
I have a trouble for several days and I need help to solve it.
I have an hash with multiple values for the same key :
{"answers":
[
{"id":1,"value":true},
{"id":3,"value":false},
{"id":2,"value":3},
{"id":1,"value":false},
{"id":2,"value":false},
{"id":2,"value":1}
]
}
I want a method to group all the values for one key, as an exemple :
{
"answers": [
{
"id":1, "value": [true, false]
},
{
"id":3, "value": [false]
},
{
"id":2, "value":[3, false, 1]
}
]
}
I've tried with the reduce method, but I cant find a way to link values to keys.
Anyone can help me with that ?
Thanks!
It looks like you want Enumerable#group_by to regroup the array of hashes by the :id key in each hash.
This method takes the answers array and returns a new, transformed answers array:
def transform_answers(answers)
answers
.group_by { |h| h[:id] }
.each_value { |a| a.map! { |h| h[:value] } }
.map { |id, value| { id: id, value: value } }
end
You can use it like this:
hash = {
answers: [
{ id: 1, value: true },
{ id: 1, value: false },
{ id: 2, value: 3 },
{ id: 2, value: false },
{ id: 2, value: 1 },
{ id: 3, value: false }
]
}
transformed_answers = transform_answers(hash[:answers]) # => [{:id=>1, :value=>[true, false]}, {:id=>2, :value=>[3, false, 1]}, {:id=>3, :value=>[false]}]
You can easily take the transformed answers and put them back into a hash resembling the original input:
transformed_hash = { answers: transformed_answers }
hash = {
answers: [
{ id: 1, value: true },
{ id: 1, value: false },
{ id: 2, value: 3 },
{ id: 2, value: false },
{ id: 2, value: 1 },
{ id: 3, value: false }
]
}
def doit(answers)
answers.each_with_object({}) do |g,h|
h.update(g[:id]=>{ id: g[:id], value: [g[:value]] }) do |_,o,n|
{ id: o[:id], value: o[:value]+n[:value] }
end
end.values
end
{ answers: doit(hash[:answers]) }
#=> {:answers=>[
# {:id=>1, :value=>[true, false]},
# {:id=>2, :value=>[3, false, 1]},
# {:id=>3, :value=>[false]}
# ]
# }
This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged. That block is
do |_k,o,n|
{ id: o[:id], value: o[:value]+n[:value] }
end
See the doc for update for definitions of the three block variables, _k, o and n. I've written the first block variable (the common key) _k, rather than k, to signify that it is not used in the block calculation.
Note that before values is executed in doit the method has constructed the following hash.
{1=>{:id=>1, :value=>[true, false]},
2=>{:id=>2, :value=>[3, false, 1]},
3=>{:id=>3, :value=>[false]}}
I have a ruby hash which looks like:
{ id: 123, name: "test" }
I would like to convert it to:
{ "id" => 123, "name" => "test" }
If you are using Rails or ActiveSupport:
hash = { id: 123, description: "desc" }
hash.stringify #=> { "id" => 123, "name" => "test" }
If you are not:
hash = { id: 123, name: "test" }
Hash[hash.map { |key, value| [key.to_s, value] }] #=> { "id" => 123, "name" => "test" }
I love each_with_object in this case :
hash = { id: 123, name: "test" }
hash.each_with_object({}) { |(key, value), h| h[key.to_s] = value }
#=> { "id" => 123, "name" => "test" }
In pure Ruby (without Rails), you can do this with a combination of Enumerable#map and Array#to_h:
hash = { id: 123, name: "test" }
hash.map{|key, v| [key.to_s, v] }.to_h
{ id: 123, name: "test" }.transform_keys(&:to_s)
#=> {"id"=>123, "name"=>"test"}
See Hash#transform_keys.
I've got an array full of hashes of which I want to combine specific keys to a new one, e.g.
[{ firstname: 'john', lastname: 'doe', something: 'else', key: ... }, { firstname: 'Joe', lastname: 'something', something: 'bla', key:... }]
should become
[{ name: 'john doe' },{ name: 'Joe something' }]
Please note: there are more keys in the hash as first and lastname. Is there a common ruby method to do this? Thanks!
Just do as
array = [{ firstname: 'john', lastname: 'doe' }, { firstname: 'Joe', lastname: 'something' }]
array.map { |h| { :name => h.values_at(:firstname, :lastname) * " " } }
# => [{:name=>"john doe"}, {:name=>"Joe something"}]
Read this Hash#values_at and Array#* .
This is:
a = [{ firstname: 'john', lastname: 'doe' }, { firstname: 'Joe', lastname: 'something' }]
a.map { |n| { name: n.values.join(' ') } }
# => [{:name=>"john doe"}, {:name=>"Joe something"}]
I have a nested hash like this:
LANGUAGE_DETAILS = {
BG: {
Name: 'Български',
Flag: ''
},
EN: {
Name: 'English',
Flag: ''
},
RU: {
Name: 'Руский',
Flag: ''
},
UK: {
Name: 'Украински',
Flag: ''
}
}
and need to format it like the following hash:
{
BG: 'Български',
EN: 'English',
RU: 'Руский',
UK: 'Украински'
}
in order to use it as simple_form input parameter like this:
<%= f.input :language_code, collection: SecurityUser::LANGUAGE_DETAILS,
label_method: :last,
value_method: :first,
as: :radio_buttons , label: 'Choose language' %>
Is there a way to transform the SecurityUser::LANGUAGE_DETAILS hash into new one in this context or I should create the hash on hand in the model?
You can do it like this:
Hash[LANGUAGE_DETAILS.map{|k, h| [k, h[:Name]]}]