1

I have an array of hashes who looks like :

[{"PROJECT"=>"awesome_project1","VERSION"=>128, "STATUS"=>"not required"},
 {"PROJECT"=>"awesome_project2", "VERSION"=>32, "STATUS"=>"finished"},
 {"PROJECT"=>"awesome_project1", "VERSION"=>64, "STATUS"=>"scheduled"}]

And I'm trying to merge the hashes based on one of the hask key, knowing that the key to group_by can change. So if I want to group_by "PROJECT" it would looks like :

[{"PROJECT"=>"awesome_project1","VERSION"=>[128,64], "STATUS"=>["not required","scheduled"]},
 {"PROJECT"=>"awesome_project2", "VERSION"=>32, "STATUS"=>"finished"}]

For the moment the closest I am to the result is by using group_by.

Do you have an idea on how to do it ?

1
  • It would be a kindness if you were to pretty print your objects rather than making us do it for you. Commented Jul 22, 2019 at 17:04

2 Answers 2

2

You need to group_by and then reduce values merging them.

input.
  group_by { |h| h["PROJECT"] }.
  values.
  map do |v|
    v.reduce({}) do |acc, h|
      acc.merge(h) { |_, v1, v2| v1 == v2 ? v1 : [*v1, *v2] }
    end
  end

#⇒ [{"PROJECT"=>"awesome_project1",
#    "VERSION"=>[128, 64],
#    "STATUS"=>["not required", "scheduled"]},
#   {"PROJECT"=>"awesome_project2",
#    "VERSION"=>32,
#    "STATUS"=>"finished"}]
Sign up to request clarification or add additional context in comments.

1 Comment

No need for values. since it is followed by map.
0

You can always solve problems of this kind in one of two ways. The first is to use Enumerable#group_by, as @Aleksei (aka mudsie) has done. The other way is to create a hash whose keys are the values over which the aggregation is being done (here the values of "PROJEXT"), then at the end extract the values of that hash. That's the approach I've taken below.

Code

def doit(arr)
  arr.each_with_object({}) do |g,h|
    h.update(g["PROJECT"]=>(g.merge("STATUS"=>[g["STATUS"]]))) do |_,o1,n1|
      o1.merge(n1) { |k2,o2,n2| k2=="STATUS" ? (o2+n2) : o2 }  
    end
  end.values
end

Example

arr = [
  {"PROJECT"=>"awesome_project1", "VERSION"=>128, "STATUS"=>"not required"},
  {"PROJECT"=>"awesome_project2", "VERSION"=> 32, "STATUS"=>"finished"},
  {"PROJECT"=>"awesome_project1", "VERSION"=> 64, "STATUS"=>"scheduled"}
]

doit arr
  #=> [{"PROJECT"=>"awesome_project1", "VERSION"=>128,
  #       "STATUS"=>["not required", "scheduled"]},
  #    {"PROJECT"=>"awesome_project2", "VERSION"=>32,
  #       "STATUS"=>["finished"]}] 

This is not quite the return value you asked for. In the second hash you wanted "STATUS"=>"finished", not "STATUS"=>["finished"]. I intentionally made the value an array, however, as it nearly always saves trouble down-the-line by making all values instances of the same class (here arrays). If it must be "STATUS"=>"finished", let me know and I will edit my answer.

Explanation

...under construction

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.