简体   繁体   中英

Ruby converting Array of Arrays into Array of Hashes

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM