"1", "a_1_b" => "2", "a_1_c" => "3", "a_2_a" => "3", "a_2_b" => "4", "a_2_c" => "...">

Multiple hashes from one hash

I have a hash:

hash = {"a_1_a" => "1", "a_1_b" => "2", "a_1_c" => "3", "a_2_a" => "3", "a_2_b" => "4", "a_2_c" => "4"} 

What is the best way to get the following sub-hashes:

 [{"a_1_a" => "1", "a_1_b" => "2", "a_1_c" => "3"}, {"a_2_a" => "3", "a_2_b" => "4", "a_2_c" => "4"}] 

I want them to be grouped by key, based on regexp /^a_(\d+)/ . I will have 50+ key / value pairs in the original hash, so something dynamic will work best if anyone has suggestions.

+6
source share
2 answers

If you care only about the middle component, you can use group_by to get most of the way from you:

 hash.group_by do |k,v| k.split('_')[1] end.values.map do |list| Hash[list] end # => [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}] 

The final step is to extract the grouped lists and merge them back into the required hashes.

+7
source

the code

 def partition_hash(hash) hash.each_with_object({}) do |(k,v), h| key = k[/(?<=_).+(?=_)/] h[key] = (h[key] || {}).merge(k=>v) end.values end 

Example

 hash = {"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3", "a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"} partition_hash(hash) #=> [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, # {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}] 

Explanation

Following are the steps.

 enum = hash.each_with_object({}) #=> #<Enumerator: {"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3", "a_2_a"=>"3", # "a_2_b"=>"4", "a_2_c"=>"4"}:each_with_object({})> 

The first element of this counter is generated and passed to the block, and block variables are calculated using parallel assignment.

 (k,v), h = enum.next #=> [["a_1_a", "1"], {}] k #=> "a_1_a" v #=> "1" h #=> {} 

and block calculation is performed.

 key = k[/(?<=_).+(?=_)/] #=> "1" h[key] = (h[key] || {}).merge(k=>v) #=> h["1"] = (h["1"] || {}).merge("a_1_a"=>"1") #=> h["1"] = (nil || {}).merge("a_1_a"=>"1") #=> h["1"] = {}.merge("a_1_a"=>"1") #=> h["1"] = {"a_1_a"=>"1"} 

so now

 h #=> {"1"=>{"a_1_a"=>"1"}} 

The next enum value is now generated and passed to the block, and the following calculations are performed.

 (k,v), h = enum.next #=> [["a_1_b", "2"], {"1"=>{"a_1_a"=>"1"}}] k #=> "a_1_b" v #=> "2" h #=> {"1"=>{"a_1_a"=>"1"}} key = k[/(?<=_).+(?=_)/] #=> "1" h[key] = (h[key] || {}).merge(k=>v) #=> h["1"] = (h["1"] || {}).merge("a_1_b"=>"2") #=> h["1"] = ({"a_1_a"=>"1"}} || {}).merge("a_1_b"=>"2") #=> h["1"] = {"a_1_a"=>"1"}}.merge("a_1_b"=>"2") #=> h["1"] = {"a_1_a"=>"1", "a_1_b"=>"2"} 

After the remaining four enum elements have been passed to the block, the following is returned.

 h #=> {"1"=>{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, # "2"=>{"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}} 

The final step is to simply extract the values.

 h.values #=> [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, # {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}] 
+4
source

Source: https://habr.com/ru/post/1013011/


All Articles