sijpkes sijpkes - 3 months ago 11
Ruby Question

Modifying reference to hash value in Ruby

I'm new to Ruby and I have a JSON data set that I am de-identifying using stympy's Faker. I would prefer to change the values in the Hash by reference.

I've tried changing the assignments eg.

key['v] = namea[1]
to
data['cachedBook']['rows'][key][value] = namea[1]
but I get a
no implicit conversion of Array into String
error. Which makes sense since each is an array in itself, but I'm unsure as to how proceed on this.

A single row e.g.
data['cachedBook']['rows']
looks like this:

[{"v":"Sijpkes_PreviewUser","c":"LN","uid":"9######","iuid":"3####7","avail":true,"sortval":"Sijpkes_PreviewUser"},
{"v":"Paul","c":"FN","sortval":"Paul"},
{"v":"#####_previewuser","c":"UN"},
{"v":"","c":"SI"},{"v":"30 June 2016","c":"LA","sortval":1467261918000},
{"v":"Available","c":"AV"},[],[],[],[],[],[],
{"v":"-","tv":"","numAtt":"0","c":"374595"},[],[],
{"v":"-","tv":"","numAtt":"0","c":"374596"},[],[],[],
{"v":0,"tv":"0.0","mp":840,"or":"y","c":"362275"},
{"v":0,"tv":"0.0","mp":99.99999,"or":"y","c":"389721"}]


The key and value are interpreted as the first two entries.
Sensitive data has been removed with
####
s.

Ruby code:

data['cachedBook']['rows'].each do |key, value|
fullname = Faker::Name.name
namea = fullname.split(' ')

str = "OLD: " + String(key['v']) + " " + String(value['v']) +"\n";
puts str

if ["Ms.", "Mr.", "Dr.", "Miss", "Mrs."].any? { |needle| fullname.include? needle }
key['v'] = namea[2]
value['v'] = namea[1]
value['sortval'] = namea[1]
else
key['v'] = namea[1]
value['v'] = namea[0]
value['sortval'] = namea[1]
end

str = "\nNEW: \nFullname: "+String(fullname)+"\nConverted surname: "+ String(key['v']) + "\n\t firstname: " + String(value['v'])
puts str
end

puts data

Answer

OK, this has been an excellent learning exercise!

The problem I was having was in two parts:

  1. the JSON output from JSON.parse was a Hash, but the Hash was storing Arrays, so my code was breaking. Looking at the sample data rows above, it includes some empty arrays: ... [],[],[] ....

  2. I misunderstood how each was working with a Hash, I assumed key, value (similar to jquery each) but the key, value in the original each statement actually evaluated to the first two array elements.

So here is my amended code:

data['cachedBook']['rows'].map! { |row|
  fullname = Faker::Name.name
  namea = fullname.split(' ')

  row.each { |val|

  if val.class == Hash
      newval = val.clone
        if ["Ms.", "Mr.", "Dr.", "Miss", "Mrs."].any? { |needle| fullname.include? needle  }
              if val.key?("c") && val["c"] == "LN"
                newval["v"] = namea[1]
                newval["sortval"] = namea[1]
              end
              if val.key?("c") && val["c"] == "FN"
                newval["v"] = namea[2]
                newval["sortval"] = namea[2]
              end
        else
            if val.key?("c") && val["c"] == "LN"
              newval["v"] = namea[0]
              newval["sortval"] = namea[0]
            end
            if val.key?("c") && val["c"] == "FN"
              newval["v"] = namea[1]
              newval["sortval"] = namea[1]
            end
        end
    val.merge!(newval)
  end
  }
}
Comments