Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Passing down key/value after transforming objects in array

Given data:

data = [
 {"id":14, "sort":1, "content":"9", foo: "2022"},
 {"id":14, "sort":4, "content":"5", foo: "2022"},
 {"id":14, "sort":2, "content":"1", foo: "2022"},
 {"id":14, "sort":3, "content":"0", foo: "2022"},
 {"id":15, "sort":4, "content":"4", foo: "2888"},
 {"id":15, "sort":2, "content":"1", foo: "2888"},
 {"id":15, "sort":1, "content":"3", foo: "2888"},
 {"id":15, "sort":3, "content":"3", foo: "2888"},
 {"id":16, "sort":1, "content":"8", foo: "3112"},
 {"id":16, "sort":3, "content":"4", foo: "3112"},
 {"id":16, "sort":2, "content":"4", foo: "3112"},
 {"id":16, "sort":4, "content":"9", foo: "3112"}
]

Got the contents concatenated by their sort and ids with:

formatted = data.group_by { |d| d[:id]}.transform_values do |value_array|
  value_array.sort_by { |b| b[:sort] }
             .map     { |c| c[:content] }.join
end

puts formatted
#=> {14=>"9105", 15=>"3134", 16=>"8449"}

I know that foo exists inside value_array but wondering how can I include foo to exist inside the formatted variable so I can map through it to get the desired output or if it's possible?

Desired Output:

[
 {"id":14, "concated_value":"9105", foo: "2022"},
 {"id":15, "concated_value":"3134", foo: "2888"},
 {"id":16, "concated_value":"8449", foo: "3112"}
]
like image 544
endex Avatar asked Jul 13 '18 17:07

endex


1 Answers

Since :foo is unique to :id. You can do this as follows:

data.group_by {|h| h[:id]}.map do |_,sa| 
  sa.map(&:dup).sort_by {|h| h.delete(:sort) }.reduce do |m,h| 
     m.merge(h) {|key,old,new| key == :content ? old + new : old } 
  end.tap {|h| h[:concated_value] = h.delete(:content) }
end  
#=> [
# {"id":14, foo: "2022", "concated_value":"9105"},
# {"id":15, foo: "2888", "concated_value":"3134"},
# {"id":16, foo: "3112", "concated_value":"8449"}
# ]
  • First we group by id. group_by {|h| h[:id]}
  • Then we dup the hashes in the groups (so as not to destory the original). map(&:dup)
  • Then we sort by sort and delete it at the same time. .sort_by {|h| h.delete(:sort) }
  • Then we merge the groups together and concatenate the content key only. m.merge(h) {|key,old,new| key == :content ? old + new : old }
  • Then we just change the key for content to concated_value tap {|h| h[:concated_value] = h.delete(:content) }
like image 79
engineersmnky Avatar answered Sep 30 '22 15:09

engineersmnky