2

I have a following array which displays information of users and some values related to the user. Following array contains information of two users Akiyo Riggs and Bingo

a1 = [["Akiyo Riggs", -32, "OverTime Hours", "",12],["Akiyo Riggs", -32, 
"Regular Hours", "", 18],["Bingo",-12,"OverTime Hours","",14], ["Bingo",
-12,"Regular Hours","",32]]

How can i convert into following array of hashes in which key is the user name and value is a hash with respective values

[{"Akiyo Riggs"=>{"OverTime Hours"=>["", 12], "Regular Hours"=>["", 18]},
{"Bingo"=>{"OverTime Hours"=>["", 14], "Regular Hours"=>["", 32]}]
1
  • 1
    You can do it in many ways. But what have you tried already ? Can u show us the code so we could help in fixing it ? Commented Dec 8, 2014 at 12:25

4 Answers 4

4
a1.map { |x,_,p,*ps| {x => {p => ps} } }.reduce({}, :deep_merge)
# => {"Akiyo Riggs"=>{"OverTime Hours"=>["", 12], "Regular Hours"=>["", 18]},
#     "Bingo"=>{"OverTime Hours"=>["", 14], "Regular Hours"=>["", 32]}}

Note: if efficiency is concerned, consider using deep_merge! instead of deep_merge, so that reduce wouldn't create a new hash on every iteration.

Some explanation:

a1.map { |x,_,p,*ps| {x => {p => ps} } }

gives us an array of hashes like this

 [{"Akiyo Riggs"=>{"OverTime Hours"=>["", 12]}},
  {"Akiyo Riggs"=>{"Regular Hours"=>["", 18]}},
  {"Bingo"=>{"OverTime Hours"=>["", 14]}},
  {"Bingo"=>{"Regular Hours"=>["", 32]}}]

which we can recursively merge with ActiveSupport Hash#deep_merge

Sign up to request clarification or add additional context in comments.

4 Comments

Author asked for Array, but you return hash.
The hash form is arguably more useful.
@MarkThomas of course, but that's still not an answer to author's question. btw this variant is 2 times slower that others.
Well I still think it qualifies as a good answer, as it is likely to get OP started on a solution.
2

You can do something like this (however, this is not quite that is you want exactly):

res = a1.group_by {|x| x[0] }.reduce({}) {|h, x| h[ x[0] ] = x[1].reduce({}) {|hh, xx| hh[ xx[2] ] = xx[3..-1] ; hh } ; h }
# => {"Akiyo Riggs"=>{"OverTime Hours"=>["", 12], "Regular Hours"=>["", 18]}, "Bingo"=>{"OverTime Hours"=>["", 14], "Regular Hours"=>["", 32]}}

the exact thing is doing with additional step:

res.keys.map {|k| {k => res[k]}}
# => [{"Akiyo Riggs"=>{"OverTime Hours"=>["", 12], "Regular Hours"=>["", 18]}}, {"Bingo"=>{"OverTime Hours"=>["", 14], "Regular Hours"=>["", 32]}}]

1 Comment

is it the best way @Malo
1
a1.each_with_object({}) do |array, result|
  result[array[0]] ||= {}
  result[array[0]].merge!(array[2] => [array[3], array[4]])
end.map { |k, v| { k => v } }

# => [{"Akiyo Riggs"=>{"OverTime Hours"=>["", 12], "Regular Hours"=>["", 18]}}, {"Bingo"=>{"OverTime Hours"=>["", 14], "Regular Hours"=>["", 32]}}] 

Comments

1
array.each_with_object({}) do |(name, _, hours_type, a, b), hash|
  hash[name] ||= {}
  hash[name][hours_type] = [a, b]
end.map do |name, values_hash|
  {name => values_hash}
end

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.