About array to hash conversion

H

Holden Holden

Hi,

I want to convert an array (with pairs [key,value]) to a hash. After
googling a bit I got:

1) Hash[*array.flatten]

But this is not safe as Array#flatten is recursive.

2) array.inject({}) { |m, e| m[e[0]] = e[1]; m }

Too ugly to consider.

3) Hash[*array.flatten(1)]

That's my own attempt. It only works for Ruby > 1.9.

But I am still wondering why...

- Array objects have no "to_h" method?
- Hasy[*array] don't accept the [key,value] pairs (as Hash#to_a calls
return)?

thanks,
holden
 
J

Jeremy Weiskotten

You could open up the Array class and add a to_hash method that uses the
ugly inject idiom to make it more convenient.
 
Y

yermej

Hi,

I want to convert an array (with pairs [key,value]) to a hash. After
googling a bit I got:

1) Hash[*array.flatten]

But this is not safe as Array#flatten is recursive.

2) array.inject({}) { |m, e| m[e[0]] = e[1]; m }

Too ugly to consider.

3) Hash[*array.flatten(1)]

That's my own attempt. It only works for Ruby > 1.9.

But I am still wondering why...

- Array objects have no "to_h" method?
- Hasy[*array] don't accept the [key,value] pairs (as Hash#to_a calls
return)?

These would only work in one specific case. What would this do?

[1, 2, 3].to_h
 
W

Wally T Terrible

I just did this myself. Because I knew how the data was stored in the
array, I was able to control how I put it into the hash. What I did was
this:
myArray=['255','10','258','08','154','34'] #(etc)
myHash={}
c=0
while c<=myArray.size
myHash.store(myArray[c],myArray[c+1])
c+=2
end

I don't suggest that this absolutely the best way to do it, and it may
not work if you don't know your data structure in the array but it was a
quick and easy way for me to solve my problem.
 
D

Daniel Sheppard

I want to convert an array (with pairs [key,value]) to a hash. After
googling a bit I got:
=20
1) Hash[*array.flatten]
=20
But this is not safe as Array#flatten is recursive.
=20
2) array.inject({}) { |m, e| m[e[0]] =3D e[1]; m }
=20
Too ugly to consider.

array.inject({}) {|h,(k,v)| h[k]=3Dv; h}

is still ugly, but perhaps you may consider it.

Also, arrays of arrays can be used directly in a hash-like manner:

array =3D [[1,2],[3,4]]
array.assoc(3)
=3D> [3,4]

which may be useful, depending on what you're doing (it won't have hash
performance, but it may do)

Dan.
 
R

Robert Klemme

2008/1/9 said:
I want to convert an array (with pairs [key,value]) to a hash. After
googling a bit I got:

1) Hash[*array.flatten]

But this is not safe as Array#flatten is recursive.

2) array.inject({}) { |m, e| m[e[0]] = e[1]; m }

Too ugly to consider.

You can do this:

array.inject({}) {|ha, (k, v)| ha[k] = v; ha}

Is this nicer according to your standards?

Kind regards

robert
 
H

Holden Holden

yermej said:
These would only work in one specific case. What would this do?

[1, 2, 3].to_h

That's why I prefer [key, value] pairs, to avoid any ambiguity.

However, a theorical [1,2,3].to_h should give the same error than
Hash[*array] gives:

irb(main):002:0> Hash[*[1,2,3]]
ArgumentError: odd number of arguments for Hash
 
H

Holden Holden

Robert said:
You can do this:

array.inject({}) {|ha, (k, v)| ha[k] = v; ha}

Is this nicer according to your standards?

Thanks. Yes, it's clearer to separate key/value on the args. I must
clarify that by "too ugly to consider" I meant "I imagine there is a
nicer way to do it".

Inject solutions are fine, short and clear, but I am still puzzled why
Hash[*array] and Hash#to_a are not specular (maybe this is a question
for a ruby-dev forum, though)

regards
 
S

Stefan Rusterholz

Holden said:
yermej said:
These would only work in one specific case. What would this do?

[1, 2, 3].to_h

That's why I prefer [key, value] pairs, to avoid any ambiguity.

However, a theorical [1,2,3].to_h should give the same error than
Hash[*array] gives:

irb(main):002:0> Hash[*[1,2,3]]
ArgumentError: odd number of arguments for Hash

I disagree. Array#to_hash should work so that hash.to_a.to_hash == hash,
in other words it should create a hash only if it contains key value
tuples.
array.inject({}) {|ha, (k, v)| ha[k] = v; ha}

There's absolutely no advantage using inject like this.
h={}; array.each { |k,v| h[k]=v }
Is less code and faster.
ar.to_enum:)each_with_index).inject({}) {|h, (v,k)| h[k]=v;h}
Same here
h={}; array.each_with_index { |k,v| h[k]=v }

Personally I use the following code in my lib:
# create a hash from an array with keys and an array with values
# you can set default or provide a block just as with Hash::new
def Hash.zip(keys, values, default=nil, &block)
hash = block_given? ? Hash.new(&block) : Hash.new(default)
keys.zip(values) { |k,v| hash[k]=v }
hash
end

class Array
# create a hash from an array of [key,value] tuples
# you can set default or provide a block just as with Hash::new
# Note: if you use [key, value1, value2, value#], hash[key] will
# be [value1, value2, value#]
def to_hash(default=nil, &block)
hash = block_given? ? Hash.new(&block) : Hash.new(default)
each { |(key, *value)| hash[key]=*value }
hash
end
end

Regards
Stefan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top