1

I have a hash and I would like the change the key order from.

{"result"=>{"data"=>[{"Quantity"=>13, "Rate"=>17.1},
                    {"Quantity"=>29,"Rate"=>3.2}, 
                    {"Quantity"=>7, "Rate"=>3.4}]}}

To:

{"result"=>{"data"=>[{"Rate"=>17.1, "Quantity"=>13}, 
                    {"Rate"=>3.2, "Quantity"=>29}, 
                    {"Rate"=>3.4, "Quantity"=>7}]}}

that can be accessed by hash["result"]["data"]. I tried;

hash["result"]["data"][0].each_value{|v| v.replace({"Rate" => v.delete("Rate")}.merge(v))}

But it gives error:

NoMethodError (undefined method `delete' for 17.1:Float):

engineersmnky
  • 25,495
  • 2
  • 36
  • 52
Shalafister's
  • 761
  • 1
  • 7
  • 34

4 Answers4

2

Try this,

hash["result"]["data"].each{|v| v.replace({"Rate" => v.delete("Rate")}.merge(v))}
Kshitij
  • 339
  • 1
  • 10
2

I think their is no need to do this much of operations. I suppose data contains your whole hash then just one map and reverse of hash will resolve your problem.

data['result']['data'] = data['result']['data'].map{|v|  Hash[v.to_a.reverse]}
Manishh
  • 1,444
  • 13
  • 23
2

Four more ways...

Reverse the order of those hash items:

hash['result']['data'].map! { |h| h.to_a.reverse.to_h }

Move "Quantity" to the end:

hash['result']['data'].each { |h| h["Quantity"] = h.delete("Quantity") }

Move the first item to the end:

hash['result']['data'].map! { |h| h.merge([h.shift].to_h) }

Force a certain given order:

keys = ["Rate", "Quantity"]
hash['result']['data'].map! { |h| keys.zip(h.values_at(*keys)).to_h }
Stefan Pochmann
  • 27,593
  • 8
  • 44
  • 107
  • Hey @Stefan Pochmann! I'm using **force a certain given order**. It maps integer values correctly but converting strings into nil. Can you help me how can I fix this? – Ekta Garg May 17 '19 at 08:15
0
hash = {a: 1, b: 2, c: 3}
hash.slice!(:b, :a)
puts hash # { :b => 2, :a => 1 }
Daniel Garmoshka
  • 5,849
  • 39
  • 40