Reputation: 6064
I have a hash which has many hash inside and the value may be an array and this array consist of many hashes, I wanted to print all key value pair, If values is array, then it has to print
"pageOfResults": "Array" # I don't want actual array here, I want the string "Array" to be printed.
Of If hash follows, then it needs to print
"PolicyPayment": "Hash"
else It needs to print key and value
Key -> "CurrencyCode":
Value-> "SGD",
Hash follows
a={
"PageOfResults": [
{
"CurrencyCode": "SGD",
"IpAddress": nil,
"InsuranceApplicationId": 6314,
"PolicyNumber": "SL10032268",
"PolicyPayment": {
"PolicyPaymentId": 2188,
"PaymentMethod": "GIRO"
},
"InsuranceProductDiscountDetail": nil,
"ProductDetails": {
"Results": [
{
"Id": 8113,
"InsuranceProductId": 382,
"ApplicationProductSelectedId": 62043,
},
"InsuranceProduct": {
"InsuranceProductId": 382,
"ProductCode": "TL70-90",
},
],
},
}
]
}
Program I have written to print these values
a.each do |key,value|
puts "key->" + key.to_s
if value.is_a?Array
value.each do |v|
v.each do |key,value|
puts "key->"+key.to_s
puts "value->"+value.to_s
end
end
else
puts "value->"+value.to_s
end
This program is printing first of level of hash and it's values, I can do recursive calls to print all values as well,
But my question is, Is there any way we can write Ruby style of code to accomplish this easily? Or any better way?
Upvotes: 0
Views: 1298
Reputation: 3798
I used the recursion
def traverse_multid_array(arr)
arr.each do |ele|
if ele.class == Array
traverse_multid_array(ele)
elsif ele.class == Hash
traverse_nested_hash(ele)
end
end
end
def traverse_nested_hash(hash)
hash.each do |key,value|
if value.class == Array
puts "#{key} => Array"
traverse_multid_array(value)
elsif value.class == Hash
puts "#{key} => Hash"
traverse_nested_hash(value)
else
puts "Key => #{key}"
puts "Value => #{value}"
end
end
end
traverse_nested_hash(a)
Output Result:
PageOfResults => Array
Key => CurrencyCode
Value => SGD
Key => IpAddress
Value =>
Key => InsuranceApplicationId
Value => 6314
Key => PolicyNumber
Value => SL10032268
PolicyPayment => Hash
Key => PolicyPaymentId
Value => 2188
Key => PaymentMethod
Value => GIRO
Key => InsuranceProductDiscountDetail
Value =>
ProductDetails => Hash
Results => Array
Key => Id
Value => 8113
Key => InsuranceProductId
Value => 382
Key => ApplicationProductSelectedId
Value => 62043
InsuranceProduct => Hash
Key => InsuranceProductId
Value => 382
Key => ProductCode
Value => TL70-90
Upvotes: 1
Reputation: 110675
@pos = 0
@inc = 2
def indent() @pos += @inc end
def undent() @pos -= @inc end
def prs(str); print ' '*@pos; puts str; end
def pr(k,v); prs "key->#{k}"; prs "value->#{v}"; end
def print_values(h)
h.each do |k,v|
case v
when Array
pr(k, "Array")
indent
v.each do |h|
prs "Hash"
indent
print_values(h)
undent
end
undent
when Hash
pr(k, "Hash")
indent
print_values(v)
undent
else
pr(k,v)
end
end
end
print_values a
key->PageOfResults
value->Array
Hash
key->CurrencyCode
value->SGD
key->IpAddress
value->
key->InsuranceApplicationId
value->6314
key->PolicyNumber
value->SL10032268
key->PolicyPayment
value->Hash
key->PolicyPaymentId
value->2188
key->PaymentMethod
value->GIRO
key->InsuranceProductDiscountDetail
value->
key->ProductDetails
value->Hash
key->Results
value->Array
Hash
key->Id
value->8113
key->InsuranceProductId
value->382
key->ApplicationProductSelectedId
value->62043
Hash
key->InsuranceProduct
value->Hash
key->InsuranceProductId
value->382
key->ProductCode
value->TL70-90
Upvotes: 1
Reputation: 403
You can refine Hash::each
as described here, i.e. add this code:
module HashRecursive
refine Hash do
def each(recursive=false, &block)
if recursive
Enumerator.new do |yielder|
self.map do |key, value|
value.each(recursive=true).map do |key_next, value_next|
yielder << [[key, key_next].flatten, value_next]
end if value.is_a?(Hash)
yielder << [[key], value]
end
end.entries.each(&block)
else
super(&block)
end
end
alias_method(:each_pair, :each)
end
end
using HashRecursive
After that, this code will do exactly what you've asked for:
def whatsInside(hashOrArray)
hashOrArray.each(recursive=true) do |key, value|
type = value.class.to_s
case type
when "Array", "Hash"
puts key.pop.to_s.inspect+": "+type.inspect
value.each do |valueInArray|
whatsInside(valueInArray)
end if value.is_a?(Array)
else
puts "Key -> "+key.pop.to_s.inspect+":"
puts "Value-> "+value.inspect+","
end
end
end
whatsInside(a)
The output is following:
Key -> "CurrencyCode":
Value-> "SGD",
Key -> "IpAddress":
Value-> nil,
Key -> "InsuranceApplicationId":
Value-> 6314,
Key -> "PolicyNumber":
Value-> "SL10032268",
Key -> "PolicyPaymentId":
Value-> 2188,
Key -> "PaymentMethod":
Value-> "GIRO",
"PolicyPayment": "Hash"
Key -> "InsuranceProductDiscountDetail":
Value-> nil,
"Results": "Array"
Key -> "Id":
Value-> 8113,
Key -> "InsuranceProductId":
Value-> 382,
Key -> "ApplicationProductSelectedId":
Value-> 62043,
Key -> "InsuranceProductId":
Value-> 382,
Key -> "ProductCode":
Value-> "TL70-90",
"InsuranceProduct": "Hash"
"ProductDetails": "Hash"
However, I assume this is what you want:
def whatsInside(hashOrArray)
hashOrArray.each(recursive=true) do |key, value|
if value.is_a?(Array)
puts "Entering array #{key}"
value.each { |valueInArray| whatsInside(valueInArray) }
else
puts "#{key} => #{value}" unless value.is_a?(Hash)
end
end
end
whatsInside(a)
Will return this:
Entering array [:PageOfResults]
[:CurrencyCode] => SGD
[:IpAddress] =>
[:InsuranceApplicationId] => 6314
[:PolicyNumber] => SL10032268
[:PolicyPayment, :PolicyPaymentId] => 2188
[:PolicyPayment, :PaymentMethod] => GIRO
[:InsuranceProductDiscountDetail] =>
Entering array [:ProductDetails, :Results]
[:Id] => 8113
[:InsuranceProductId] => 382
[:ApplicationProductSelectedId] => 62043
[:InsuranceProduct, :InsuranceProductId] => 382
[:InsuranceProduct, :ProductCode] => TL70-90
Upvotes: 1
Reputation: 121000
The simple λ
would do the trick:
printer = ->(enum) do
enum.each do |k, v|
enum = [k, v].detect(&Enumerable.method(:===))
if enum.nil?
puts("Key -> #{k}\nValue -> #{v}")
else
puts ("#{k} -> 'Array'") if v.is_a?(Array)
printer.(enum)
end
end
end
printer.(a)
Producing:
PageOfResults -> 'Array'
Key -> CurrencyCode
Value -> SGD
Key -> IpAddress
Value ->
Key -> InsuranceApplicationId
Value -> 6314
Key -> PolicyNumber
Value -> SL10032268
Key -> PolicyPaymentId
Value -> 2188
Key -> PaymentMethod
Value -> GIRO
Key -> InsuranceProductDiscountDetail
Value ->
Results -> 'Array'
Key -> Id
Value -> 8113
Key -> InsuranceProductId
Value -> 382
Key -> ApplicationProductSelectedId
Value -> 62043
Key -> InsuranceProductId
Value -> 382
Key -> ProductCode
Value -> TL70-90
Upvotes: 5