Please I need a help with this.
In Ruby If I have this array of arrays
array = [["a: 1", "b:2"],["a: 3", "b:4"]]
How can I obtain this array of hashes in ruby
aoh = [{:a => "1", :b => "2"},{:a => "3", :b => "4"}]
Note that, like pointed out in the comments , this is most likely an XY-problem and instead of transforming the array the better option is to build the starting array in a better manner.
Nevertheless, you can do this in the following manner:
aoh = array.map { |array| array.to_h { |string| string.split(':').map(&:strip) } }
# => [{"a"=>"1", "b"=>"2"}, {"a"=>"3", "b"=>"4"}]
The above will give you string keys which is the safer option to go with. You can convert them to symbols, but they should only be used for trusted identifiers . When the data comes from an user or external source I would go for the above.
Converting to symbols can be done by adding the following line:
# note that this line will mutate the aoh contents
aoh.each { |hash| hash.transform_keys!(&:to_sym) }
#=> [{:a=>"1", :b=>"2"}, {:a=>"3", :b=>"4"}]
array = [["a: 1", "b:2"], ["a: 3", "b:4"]]
array.map do |a|
Hash[
*a.flat_map { |s| s.split(/: */) }.
map { |s| s.match?(/\A\d+\z/) ? s : s.to_sym }
]
end
#=> [{:a=>"1", :b=>"2"}, {:a=>"3", :b=>"4"}]
The regular expression /: */
reads, "match a colon followed by zero or more ( *
) spaces". /\\A\\d+\\z/
reads, "match the beginning of the string ( \\A
) followed by one or more ( +
) digits ( \\d
), followed by the end of the string ( \\z
).
The steps are as follows. The first is for the element arr[0]
to be passed to the block, the block variable a
assigned its value and the block calculation performed.
a = array[0]
#=> ["a: 1", "b:2"]
b = a.flat_map { |s| s.split(/: */) }
#=> ["a", "1", "b", "2"]
c = b.map { |s| s.match?(/\A\d+\z/) ? s : s.to_sym }
#=> [:a, "1", :b, "2"]
d = Hash[*c]
#=> {:a=>"1", :b=>"2"}
We see the array ["a: 1", "b:2"]
is mapped to {:a=>"1", :b=>"2"}
. Next the element arr[1]
is passed to the block, the block variable a
is assigned its value and the block calculation is performed.
a = array[1]
#=> ["a: 3", "b:4"]
b = a.flat_map { |s| s.split(/: */) }
#=> ["a", "3", "b", "4"]
c = b.map { |s| s.match?(/\d/) ? s : s.to_sym }
#=> [:a, "3", :b, "4"]
d = Hash[*c]
#=> {:a=>"3", :b=>"4"}
The splat operator ( *
) causes Hash[*c]
to be evaluated as:
Hash[:a, "3", :b, "4"]
See Hash::[] .
Loop through your items, loop through its items, create a new array:
array.map do |items|
items.map do |item|
k,v = item.split(":", 2)
{ k.to_sym => v }
}
}
Note that we're using map
instead of each
which will return an array.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.