0

What is the best way to achieve the following, I have following array of actions under ABC

ABC:-

ABC:Actions,
ABC:Actions:ADD-DATA,
ABC:Actions:TRANSFER-DATA,
ABC:Actions:EXPORT,
ABC:Actions:PRINT,
ABC:Detail,
ABC:Detail:OVERVIEW,
ABC:Detail:PRODUCT-DETAIL,
ABC:Detail:EVENT-LOG,
ABC:Detail:ORDERS 

I want to format this as:

ABC =>{Actions=> [ADD-DATA,TRANSFER-DATA,EXPORT,PRINT], Detail => [Overview, Product-detail, event-log,orders]}

1
  • You have two arrays? One with the Actions and another one with Detail or it's all in the same array? Commented Jun 18, 2013 at 16:59

3 Answers 3

2

There's probably a ton of ways to do it but here's one:

a = ["ABC:Actions",
"ABC:Actions:ADD-DATA",
"ABC:Actions:TRANSFER-DATA",
"ABC:Actions:EXPORT",
"ABC:Actions:PRINT",
"ABC:Detail",
"ABC:Detail:OVERVIEW",
"ABC:Detail:PRODUCT-DETAIL",
"ABC:Detail:EVENT-LOG",
"ABC:Detail:ORDERS"]

a.map { |action| action.split(":") }.inject({}) do |m, s|
  m[s.at(0)] ||= {}
  m[s.at(0)][s.at(1)] ||= [] if s.at(1)
  m[s.at(0)][s.at(1)] << s.at(2) if s.at(2)
  m
end

The map call returns an array where each of the strings in the original array have been split into an array of elements that were separated by :. For example [["ABC","Actions","ADD-DATA"] ... ]

The inject call then builds up a hash by going through each of these "split" arrays. It creates a mapping for the first element, if one doesn't already exist, to an empty hash, e.g. "ABC" => {}. Then it creates a mapping in that hash for the second element, if one doesn't already exist, to an empty array, e.g. "ABC" => { "Detail" => [] }. Then it adds the third element to that array to give something like "ABC" => { "Detail" => ["OVERVIEW"] }. Then it goes onto the next "split" array and adds that to the hash too in the same way.

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

1 Comment

Added some explanation. Bit hard to do it succinctly though - or at least a bit hard for me :)
1

I will do this as below :

a = ["ABC:Actions",
"ABC:Actions:ADD-DATA",
"ABC:Actions:TRANSFER-DATA",
"ABC:Actions:EXPORT",
"ABC:Actions:PRINT",
"ABC:Detail",
"ABC:Detail:OVERVIEW",
"ABC:Detail:PRODUCT-DETAIL",
"ABC:Detail:EVENT-LOG",
"ABC:Detail:ORDERS"]

m = a.map{|i| i.split(":")[1..-1]}
# => [["Actions"],
#     ["Actions", "ADD-DATA"],
#     ["Actions", "TRANSFER-DATA"],
#     ["Actions", "EXPORT"],
#     ["Actions", "PRINT"],
#     ["Detail"],
#     ["Detail", "OVERVIEW"],
#     ["Detail", "PRODUCT-DETAIL"],
#     ["Detail", "EVENT-LOG"],
#     ["Detail", "ORDERS"]]

m.each_with_object(Hash.new([])){|(i,j),ob| ob[i] = ob[i] + [j] unless j.nil? }
# => {"Actions"=>["ADD-DATA", "TRANSFER-DATA", "EXPORT", "PRINT"],
#     "Detail"=>["OVERVIEW", "PRODUCT-DETAIL", "EVENT-LOG", "ORDERS"]}

Comments

1

It was just interesting to do it with group_by :)

a = ['ABC:Actions',
'ABC:Actions:ADD-DATA',
'ABC:Actions:TRANSFER-DATA',
'ABC:Actions:EXPORT',
'ABC:Actions:PRINT',
'ABC:Detail',
'ABC:Detail:OVERVIEW',
'ABC:Detail:PRODUCT-DETAIL',
'ABC:Detail:EVENT-LOG',
'ABC:Detail:ORDERS']

result = a.map { |action| action.split(":") }.group_by(&:shift)
result.each do |k1,v1|
  result[k1] = v1.group_by(&:shift)
  result[k1].each { |k2,v2| result[k1][k2] = v2.flatten }
end 

p result 

{"ABC"=>{"Actions"=>["ADD-DATA", "TRANSFER-DATA", "EXPORT", "PRINT"], "Detail"=>["OVERVIEW", "PRODUCT-DETAIL", "EVENT-LOG", "ORDERS"]}}

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.