Rajagopalan
Rajagopalan

Reputation: 6064

Need to print all the values in the nested hash

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

Answers (4)

Satishakumar Awati
Satishakumar Awati

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

Cary Swoveland
Cary Swoveland

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

MOPO3OB
MOPO3OB

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

Aleksei Matiushkin
Aleksei Matiushkin

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

Related Questions