Forum: Ruby Write Out Then Read In Hash of Two-element Arrays

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
David B. (Guest)
on 2006-04-20 13:00
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
Peter S. (Guest)
on 2006-04-20 13:19
(Received via mailing list)
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 S. (Guest)
on 2006-04-20 13:22
(Received via mailing list)
Sorry,

fileOut.puts(histHash[i])

should be replaced with

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

Cheers,
Peter
Farrel L. (Guest)
on 2006-04-20 13:22
(Received via mailing list)
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
David B. (Guest)
on 2006-04-20 22:56
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
David B. (Guest)
on 2006-04-20 22:58
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
This topic is locked and can not be replied to.