About array to hash conversion

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.

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

Too ugly to consider.

  1. 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

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

class Array
def to_hash
inject({}) { |m, e| m[e[0]] = e[1]; m }
end
end

On Jan 9, 3:31 pm, Holden H. [email protected] wrote:

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

[1, 2, 3].to_h

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.

2008/1/9, Holden H. [email protected]:

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.

  1. 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

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.

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

Too ugly to consider.

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

is still ugly, but perhaps you may consider it.

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

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

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

Dan.

yermej wrote:

On Jan 9, 3:31�pm, Holden H. [email protected] wrote:

return)?
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

2008/1/10, Holden H. [email protected]:

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

There is however one issue with a general Array to Hash conversion
routine: there are different ways to convert a Hash and to me it’s not
clear which one should be the default. Options I can see so far:

  1. if array contains pairs use them as key and value for the Hash

  2. if array is flat use consecutive entries for key and value (fails
    with odd number of entries)

  3. use indexes as keys and entries as values, e.g.

ar.to_enum(:each_with_index).inject({}) {|h, (v,k)| h[k]=v;h}

The last one has not been mentioned so far but there might actually be
uses for this (i.e. when one wants to replace an Array with a Hash).
Dunno how often this might occur though.

There are probably other valid default conversion candidates, too.

Kind regards

robert

Robert K. wrote:

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

Holden H. wrote:

yermej wrote:

On Jan 9, 3:31�pm, Holden H. [email protected] wrote:

return)?
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

I don’t think I saw this one:

h = {}; [1,2,3,4].each_slice(2) {|k,v| h[k]=v}

Array objects have no “to_h” method?

they do

[[:one, 1], [:two, 2]].to_h
=> {:one=>1, :two=>2}

[:one, 1, :two, 2, :buckle_my, “shoe”, :three].each_slice(2).map {|a,b|
[a,b]}.to_h
=> {:one=>1, :two=>2, :buckle_my=>“shoe”, :three=>nil}

This works because each_slice returns an enumerator. cool.

I found this. Might be helpful:

http://programmingbulls.com/ruby-array-hash