What should I do to marshal an hash of arrays?
The following code only prints {}
.
s = Hash.new
s.default = Array.new
s[0] <<
You can just create your hash structure while initialing Hash.new to avoid such trouble
h = Hash.new{ |a,b| a[b] = [] }
h[:my_key] << "my value"
s = Hash.new
s.default = Array.new
s[0] << "Tigger"
s[7] << "Ruth"
s[7] << "Puuh"
This code changes the default 3 times (which is probably what showed up in the dump), but it does not store anything in the hash. Try "puts s[8]", it will return [["Tigger"], ["Ruth"], ["Puuh"]].
A Hash.default_proc will do what you want
s = Hash.new{|hash,key| hash[key]=[] }
But you can't marshall a proc. This will work:
s = Hash.new
s.default = Array.new
s[0] += ["Tigger"]
s[7] += ["Ruth"]
s[7] += ["Puuh"]
This works because []+=["Tigger"] creates a new array. An alternative, creating less arrays:
s = Hash.new
(s[0] ||= []) << "Tigger"
(s[7] ||= []) << "Ruth"
(s[7] ||= []) << "Puuh"
Only creates a new array when the key is absent (nil).
As you can't use Marshall.dump
on a Hash with a proc for the default element, you could use a slightly more roundabout way of appending to each Array instead of <<
:
s = Hash.new
s.default = []
s[0] += [ "Tigger" ]
s[7] += [ "Ruth" ]
s[7] += [ "Pooh" ]
data = Marshal.dump(s)
ls = Marshal.restore(data)
p ls
You might be misled about how Hash.default
works.
Before you Marshal.dump
, print the data structure. It is {}
. That's because you are concatenating each string into nil, not into an empty array. The code below illustrates and solves your problem.
s = Hash.new
s.default = Array.new
s[0] = []
s[0] << "Tigger"
s[7] = []
s[7] << "Ruth"
s[7] << "Puuh"
p s
data = Marshal.dump(s)
ls = Marshal.restore( data )
p ls
Returns:
{0=>["Tigger"], 7=>["Ruth", "Puuh"]}
{0=>["Tigger"], 7=>["Ruth", "Puuh"]}
EDIT:
I insert a lot of data into the hash
So maybe some helper code would make the insertion process smoother:
def append_to_hash(hash, position, obj)
hash[position] = [] unless hash[position]
hash[position] << obj
end
s = Hash.new
append_to_hash(s, 0, "Tigger")
append_to_hash(s, 7, "Ruth")
append_to_hash(s, 7, "Puuh")
s.default = Array.new // this is only for reading
p s
data = Marshal.dump(s)
ls = Marshal.restore( data )
p ls