Write Out Then Read In Hash of Two-element Arrays


#1

Kind All,

I wonder if one of you knowledgeble folks can steer me in he right
direction:

I’m trying to get a hash I’ve created read back in after after writing
it out to a file, so that it is exactly the same afterward. The hash
has zero-based integer keys and two-element array values.

After I create and populate the hash:
Length of histHash after creation = 5

When I write out the hash, the output to STDOUT looks like this:
Write histHash[0] = 101
Write histHash[1] = 112
Write histHash[2] = 123
Write histHash[3] = 134
Write histHash[4] = 145
5 histHash lines written
histHash written = 01011112212331344145

After I delete the elements of the hash:
Length of histHash after deletion = 0

But when I read it back in, it looks like this:
Read histHash[0] = 10; line = 10
Read histHash[1] = 1; line = 1
Read histHash[2] = 11; line = 11
Read histHash[3] = 2; line = 2
Read histHash[4] = 12; line = 12
Read histHash[5] = 3; line = 3
Read histHash[6] = 13; line = 13
Read histHash[7] = 4; line = 4
Read histHash[8] = 14; line = 14
Read histHash[9] = 5; line = 5
10 histHash lines read
histHash read = 5301061311742118143295412
Length of histHash after read = 10

As you can see, it’s length is five lines when I initially write it to
the file, but ten lines when I read it back in. I’ve been pawing though
the docs, but I can’t figure out what I’m doing wrong. Any help will be
greatly appreciated.

Here is the errant code:

write out and then read in hash of two-element arrays

create and populate the hash

histHash = Hash.new
histHash[0] = [10, 1]
histHash[1] = [11, 2]
histHash[2] = [12, 3]
histHash[3] = [13, 4]
histHash[4] = [14, 5]
puts
puts “Length of histHash after creation = #{histHash.length}”
puts

write the hash to the file

fileOut = File.new(“savedHash.sdo”, “w”)
histHash.length.times do |i|
fileOut.puts(histHash[i])
puts “Write histHash[#{i}] = #{histHash[i]}”
end
fileOut.close

puts “#{histHash.length} histHash lines written”
puts “histHash written = #{histHash}”
puts

Delete the hist hash elements

histHash.length.times do |i|
histHash.delete(i)
end
puts “Length of histHash after deletion = #{histHash.length}”
puts

load (read) the saved file

fileIn = File.new(“savedHash.sdo”, “r”)
i = 0
fileIn.each_line{|line|histHash[i]=[line.to_i]; puts “Read
histHash[#{i}] = #{histHash[i]}; line = #{line}”;i+=1}
fileIn.close
puts “#{histHash.length} histHash lines read”
puts “histHash read = #{histHash}”
puts “Length of histHash after read = #{histHash.length}”
puts


#2

David,

My initial guess:

puts “Write histHash[#{i}] = #{histHash[i]}”

replaced with

fileOut.print("#{histHash[i]}\n")

This is what you want?

HTH,
Peter


#3

Sorry,

fileOut.puts(histHash[i])

should be replaced with

fileOut.print("#{histHash[i]}\n")

Cheers,
Peter


#4

Instead of writing your own de/serialization code why not give
Marshal.dump and Marshal.load a try:

dumped_histHash = Marshal.dump(histHash)
=>
“\004\010{\ni\000[\ai\017i\006i\006[\ai\020i\ai\a[\ai\021i\010i\010[\ai\022i
ti\t[\ai\023i\n”

loaded_histHash = Marshal.load(dumped_histHash)
=> {0=>[10, 1], 1=>[11, 2], 2=>[12, 3], 3=>[13, 4], 4=>[14, 5]}

If you need a human readable/editable file consider using YAML:

require ‘yaml’
=> true

puts yaml_histHash = histHash.to_yaml


0:

  • 10
  • 1
    1:
  • 11
  • 2
    2:
  • 12
  • 3
    3:
  • 13
  • 4
    4:
  • 14
  • 5
    => nil

loaded_histHash = YAML.load(yaml_histHash)
=> {0=>[10, 1], 1=>[11, 2], 2=>[12, 3], 3=>[13, 4], 4=>[14, 5]}

Farrel


#5

Farrel L. wrote:

Instead of writing your own de/serialization code why not give
Marshal.dump and Marshal.load a try:

dumped_histHash = Marshal.dump(histHash)
=>
“\004\010{\ni\000[\ai\017i\006i\006[\ai\020i\ai\a[\ai\021i\010i\010[\ai\022i
ti\t[\ai\023i\n”

loaded_histHash = Marshal.load(dumped_histHash)
=> {0=>[10, 1], 1=>[11, 2], 2=>[12, 3], 3=>[13, 4], 4=>[14, 5]}

If you need a human readable/editable file consider using YAML:

require ‘yaml’
=> true

puts yaml_histHash = histHash.to_yaml


0:

  • 10
  • 1
    1:
  • 11
  • 2
    2:
  • 12
  • 3
    3:
  • 13
  • 4
    4:
  • 14
  • 5
    => nil

loaded_histHash = YAML.load(yaml_histHash)
=> {0=>[10, 1], 1=>[11, 2], 2=>[12, 3], 3=>[13, 4], 4=>[14, 5]}

Farrel

Farrel,

Good suggestion. Had I not forgotten about marshal and yaml (after
having read about it a while back in the pickaxe book), I would have
done so initally. At any rate, thank you for the suggestion. And for
jogging my memory!

David


#6

Peter S. wrote:

David,

My initial guess:

puts “Write histHash[#{i}] = #{histHash[i]}”

replaced with

fileOut.print("#{histHash[i]}\n")

This is what you want?

HTH,
Peter

Peter,

After a number of suggestions from gracious Rubyists, I am happy to say
that I am now all set. Thank you very much for your help. Best
regards,

David