Reputation: 107
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]}
Upvotes: 0
Views: 125
Reputation: 34774
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.
Upvotes: 2
Reputation: 2677
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"]}}
Upvotes: 1
Reputation: 118261
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"]}
Upvotes: 1