需要打印嵌套哈希中的所有值

时间:2018-03-16 05:57:58

标签: ruby

我有一个哈希里面有很多哈希,值可能是一个数组,这个数组由许多哈希组成,我想打印所有键值对,如果值是数组,那么它必须打印

"pageOfResults": "Array" # I don't want actual array here, I want the string "Array" to be printed. 

如果哈希如下,则需要打印

"PolicyPayment": "Hash"

其他需要打印键和值

Key  -> "CurrencyCode": 
Value-> "SGD",

哈希跟随

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",
                    },
                ],               
            },
        }
    ]
}

我编写的程序用于打印这些值

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

这个程序首先打印哈希值和它的值,我可以做递归调用来打印所有值,

但我的问题是,有没有什么方法可以编写Ruby风格的代码来轻松实现这一目标?还是更好的方式?

4 个答案:

答案 0 :(得分:4)

简单的 λ 可以解决问题:

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)

产:

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

答案 1 :(得分:1)

我使用了递归,希望这对你有所帮助。

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)

输出结果:

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

答案 2 :(得分:1)

您可以按照here所述优化Hash::each,即添加以下代码:

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

之后,此代码将完全您要求的内容:

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)

输出如下:

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"

然而,我认为这就是你想要的:

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)

将返回此:

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

答案 3 :(得分:1)

@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