cocacrave cocacrave - 4 months ago 15
JSON Question

Ruby iteration over JSON and write to a file

I have a JSON file like this:

data.json

{
"ABCD": [ ["x", "x", "x", "x"], ["x", "x", "x", "x"] ],
"EFGH": [ ["x", "x", "x", "x"], ["x", "x", "x", "x"] ],
"IJKL": [ ["x", "x", "x", "x"], ["x", "x", "x", "x"] ]
}


I'd like to iterate over the keys A1, B1, C1, etc and re-write the data.json file to look like this:

{
"ABCD": [ ["Ax", "Bx", "Cx", "Dx"], ["Ax", "Bx", "Cx", "Dx"] ],
"EFGH": [ ["Ex", "Fx", "Gx", "Hx"], ["Ex", "Fx", "Gx", "Hx"] ],
"IJKL": [ ["Ix", "Jx", "Kx", "Lx"], ["Ix", "Jx", "Kx", "Lx"] ]
}


How would I do this?
I've never used Ruby before... But I'd like to learn starting with some useful scripts.

Answer

There's a number of tricks in the Enumerable library that can help here:

require 'json'

data = JSON.load <<END
{
  "ABCD": [ ["x", "x", "x", "x"], ["x", "x", "x", "x"] ],
  "EFGH": [ ["x", "x", "x", "x"], ["x", "x", "x", "x"] ],
  "IJKL": [ ["x", "x", "x", "x"], ["x", "x", "x", "x"] ]
}
END

reworked = Hash[
  data.map do |key, values|
    letters = key.chars

    [ key, values.map { |a| letters.zip(a).map(&:join) }]
  end
]

# => {"ABCD"=>[["Ax", "Bx", "Cx", "Dx"], ["Ax", "Bx", "Cx", "Dx"]], "EFGH"=>[["Ex", "Fx", "Gx", "Hx"], ["Ex", "Fx", "Gx", "Hx"]], "IJKL"=>[["Ix", "Jx", "Kx", "Lx"], ["Ix", "Jx", "Kx", "Lx"]]}

Here Hash[] is useful for converting one hash into another, and map is used to re-write each element in the list. zip combines two arrays together like a zipper. chars is a quick way of pulling individual characters out of a string.

If you want to write this back to a file:

File.open('output.json', 'w') do |f|
  f.write(JSON.dump(reworked))
end