如何在Ruby哈希上深度转换值

时间:2019-03-11 00:59:53

标签: ruby hash transform

我有一个看起来像这样的哈希:

hash = {
  'key1' => ['value'],
  'key2' => {
    'sub1' => ['string'],
    'sub2' => ['string'],
  },
  'shippingInfo' => {
                   'shippingType' => ['Calculated'],
                'shipToLocations' => ['Worldwide'],
              'expeditedShipping' => ['false'],
        'oneDayShippingAvailable' => ['false'],
                   'handlingTime' => ['3'],
    }
  }

我需要转换数组中单个字符串的每个值,以使其最终像这样:

hash = {
  'key1' =>  'value' ,
  'key2' => {
    'sub1' => 'string' ,
    'sub2' => 'string' ,
  },
  'shippingInfo' => {
                   'shippingType' => 'Calculated' ,
                'shipToLocations' => 'Worldwide' ,
              'expeditedShipping' => 'false' ,
        'oneDayShippingAvailable' => 'false' ,
                   'handlingTime' => '3' ,
    }
  }

我找到了,但无法正常工作 https://gist.github.com/chris/b4138603a8fe17e073c6bc073eb17785

2 个答案:

答案 0 :(得分:3)

那又怎么样呢?

def deep_transform_values(hash)
  return hash unless hash.is_a?(Hash)

  hash.transform_values do |val|
    if val.is_a?(Array) && val.length == 1
      val.first
    else
      deep_transform_values(val)
    end
  end
end

经过类似以下测试:

hash = {
  'key1' => ['value'],
  'key2' => {
    'sub1' => ['string'],
    'sub2' => ['string'],
  },
  'shippingInfo' => {
                   'shippingType' => ['Calculated'],
                'shipToLocations' => ['Worldwide'],
              'expeditedShipping' => ['false'],
        'oneDayShippingAvailable' => ['false'],
                   'handlingTime' => ['3'],
                   'an_integer' => 1,
                   'an_empty_array' => [],
                   'an_array_with_more_than_one_elements' => [1,2],
                   'a_symbol' => :symbol,
                   'a_string' => 'string'
    }
  }

礼物:

{
  "key1"=>"value",
  "key2"=>{
    "sub1"=>"string",
    "sub2"=>"string"
  },
  "shippingInfo"=> {
    "shippingType"=>"Calculated",
    "shipToLocations"=>"Worldwide",
    "expeditedShipping"=>"false",
    "oneDayShippingAvailable"=>"false",
    "handlingTime"=>"3",
    "an_integer"=>1,
    "an_empty_array"=>[],
    "an_array_with_more_than_one_elements"=>[1, 2],
    "a_symbol"=>:symbol,
    "a_string"=>"string"
  }
}

在评论中提出您的问题之后,我想逻辑会有所改变:

class Hash
  def deep_transform_values
    self.transform_values do |val|
      next(val.first) if val.is_a?(Array) && val.length == 1
      next(val) unless val.respond_to?(:deep_transform_values)

      val.deep_transform_values
    end
  end
end

答案 1 :(得分:1)

hash = {
  'key1' => ['value'],
  'key2' => {
    'sub1' => ['string'],
    'sub2' => ['string'],
  },
  'shippingInfo' => {
                   'shippingType' => ['Calculated'],
                'shipToLocations' => ['Worldwide', 'Web'],
              'expeditedShipping' => ['false'],
        'oneDayShippingAvailable' => ['false'],
                   'handlingTime' => ['3'],
    }
  }

def recurse(hash)
  hash.transform_values do |v|
    case v
    when Array
      v.size == 1 ? v.first : v
    when Hash
      recurse v
    else
      # raise exception
    end
  end
end

recurse hash
  #=> {"key1"=>"value",
  #    "key2"=>{
  #      "sub1"=>"string",
  #      "sub2"=>"string"
  #    },
  #    "shippingInfo"=>{
  #      "shippingType"=>"Calculated",
  #      "shipToLocations"=>["Worldwide", "Web"],
  #      "expeditedShipping"=>"false",
  #      "oneDayShippingAvailable"=>"false",
  #      "handlingTime"=>"3"
  #    }
  #  }