3
votes

Comment transformer en profondeur les valeurs sur le hachage Ruby

J'ai un hachage qui ressemble à ceci:

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

Je dois convertir chaque valeur qui est une seule chaîne à l'intérieur d'un tableau pour qu'elle se termine comme ceci:

XXX

J'ai trouvé ceci mais je n'ai pas réussi à le faire fonctionner https://gist.github.com/chris/b4138603a8fe17e073c6bc073eb17785

p> >


0 commentaires

3 Réponses :


6
votes

Que diriez-vous de quelque chose comme:

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

Testé avec quelque chose comme:

{
  "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"
  }
}

Donne:

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'
    }
  }


4 commentaires

Cela fonctionne bien pour mon cas d'utilisation. Cependant, si je voulais monkey-patch Hash classe, comment puis-je modifier cela pour qu'il fonctionne avec la récursivité afin que je puisse l'appeler sur une instance de Hash?


J'ai mis à jour la réponse avec une variante pour votre cas @lacostenycoder.


cela fonctionne très bien. Je n'ai jamais utilisé next avec argss auparavant. Pouvez-vous m'indiquer la documentation à ce sujet?


C'est ce que le document Ruby a donc loin.



1
votes

Comme alternative, envisagez d'utiliser un objet et de permettre à l'initialiseur de déconstruire certaines des clés pour vous.

L'une des raisons pour lesquelles beaucoup de gens comme moi ont commencé à utiliser Ruby en faveur de Perl était à cause de la meilleure expression d'objets à la place de primitifs comme les tableaux et les hachages. Utilisez-le à votre avantage!

class ShippingStuff # You've kept the data vague

  def initialize key1:, key2:, shippingInfo:
    @blk = -> val {
      val.respond_to?(:push) && val.size == 1 ?
          val.first :
          cleankeys(val)
    }
    @key1 = cleankeys key1
    @key2 = cleankeys key2
    @shippingInfo = shippingInfo
  end

  attr_reader :key1, :key2, :shippingInfo

  # basically a cut down version of what
  # Sebastian Palma answered with
  def cleankeys data
    if data.respond_to? :transform_values
      data.transform_values &@blk
    else
      @blk.call(data)
    end
  end

end


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

shipper = ShippingStuff.new hash.transform_keys!(&:to_sym)
shipper.key1
# "value"
shipper.key2
# {"sub1"=>"string", "sub2"=>"string"}
shipper.shippingInfo
# {"shippingType"=>["Calculated"], "shipToLocations"=>["Worldwide"], "expeditedShipping"=>["false"], "oneDayShippingAvailable"=>["false"], "handlingTime"=>["3"]}

Dans la même veine, je créerais même une classe Info pour le code shippingInfo > data.

Vous pouvez rencontrer un problème différent si key1 et key2 sont dynamiques, mais il existe également des moyens de contourner ce problème ( double splat pour un).


2 commentaires

C'est probablement un meilleur modèle bien qu'un peu plus rigide. La structure des données ici était un exemple non spécifique,


@lacostenycoder Bien sûr, je voulais juste donner une alternative, je ne critique pas. Le "Juste mes 2 cents" le fait peut-être passer pour une critique, probablement parce que les gens l'utilisent avant de critiquer les gens, non? Je devrais trouver une phrase de remplacement… (o_º)



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

2 commentaires

Je vois que ma réponse est similaire à la réponse précédente de @ Sebastian.


oui très similaire sauf en utilisant un style de commutateur mais fonctionne toujours. cela se traduit-il bien comme un patch de singe en classe Hash?