Monday, March 14, 2011

Iterate through a variable depth nested hash in ruby

I had a hash with variable depth and wanted to get info from it without being lost in the iteration.
Essentially, this was a sort of hierarchical arrangement of diagnoses from which I wanted to get the full diagnosis name by traversing the hash to the last node and back.

Well, I fail to exactly explain what I had and what I wanted to achieve. I guess an example will do the trick.
Here is my Hash:
{
"HEART FAILURE":{
"RIGHT VENTRICULAR":{},
"LEFT VENTRICULAR":{},
"CONGESTIVE CARDIAC":{},
"OTHER":{}
},
"MYOCARDIAL INFARCTION":{},
"ANGINA":{},
"HEPATITIS":{
"ACUTE":{
"DRUG INDUCED":{},
"HEPATITIS A":{},
"HEPATITIS B":{},
"HEPATITIS C":{},
"UNEXPLAINED":{},
"OTHER":{}
},

"CHRONIC":{
"DRUG INDUCED":{},
"HEPATITIS A":{},
"HEPATITIS B":{},
"HEPATITIS C":{},
"UNEXPLAINED":{},
"OTHER":{}
},

"OTHER":{}
}
}


What I wanted to get is an array which looks like

["HEART FAILURE RIGHT VENTRICULAR",
"HEART FAILURE LEFT VENTRICULAR",
"HEART FAILURE CONGESTIVE CARDIAC",
"HEART FAILURE OTHER",
"MYOCARDIAL INFARCTION",
.
.
.
"HEPATITIS ACUTE DRUG INDUCED",
"HEPATITIS ACUTE HEPATITIS A",
.
.
.
"HEPATITIS CHRONIC OTHER",
"HEPATITIS CHRONIC UNEXPLAINED",
"HEPATITIS OTHER"
]


I hope you get the idea!

I guess what I needed was a classical Depth First Search algorithm and this is how I implemented it in Ruby.

def self.all_diagnoses(diagnosis_hash = my_hash, deep_list = [], short_list = [])
diagnosis_hash.each do |k,v|
if v.blank? #if the value is an empty hash, then we are at the last node
short_list.push k
deep_list << short_list.join(" ")
short_list.pop
else
short_list.push k
all_diagnoses(v, deep_list, short_list)
short_list.pop
end
end
deep_list.sort
end


Have tested this on a hash with up to three levels and it works!
Any observations? Post them below

No comments: