views:

121

answers:

4

I'm seeking the most concise way to do this

Given the following Array:

['a','b','c']

how to get this:

{'a'=> 1,'b'=> 2, 'c'=> 3}

and

[['a',1],['b',2],['c',3]]

I have few solutions at mind, just want to see yours :)

+2  A: 
# 1.8.7+:
['a','b','c'].each_with_index.collect {|x,i| [x, i+1]} # => [["a", 1], ["b", 2], ["c", 3]]
# pre-1.8.7:
['a','b','c'].enum_with_index.collect {|x,i| [x, i+1]}

# 1.8.7+:
Hash[['a','b','c'].each_with_index.collect {|x,i| [x, i+1]}] # => {"a"=>1, "b"=>2, "c"=>3}
# pre-1.8.7:
Hash[*['a','b','c'].enum_with_index.collect {|x,i| [x, i+1]}.flatten]
newacct
When was "enum_with_index" introduced? It doesn't exist in 1.8.5!
glenn mcdonald
+4  A: 
a.zip(1..a.length)

and

Hash[a.zip(1..a.length)]
Martin DeMello
Note that this doesn't work pre 1.8.7.
glenn mcdonald
glenn: the first one at least should work, shouldn't it?
Martin DeMello
No, both of these raise "can't convert Range into Array" as written. You have to do "a.zip((1..a.size).to_a)" for the first one, and this then raises "odd number of arguments for Hash" in the second one, so you have to do Hash[*...flatten].
glenn mcdonald
ah, thanks :) didn't have a 1.8.6 system handy to check
Martin DeMello
+1  A: 

If you want concise and fast, and 1.8.5 compatability, this is the best I've figured out:

i=0
h={}
a.each {|x| h[x]=i+=1}

The version of Martin's that works in 1.8.5 is:

Hash[*a.zip((1..a.size).to_a).flatten]

But this is 2.5x slower than the above version.

glenn mcdonald
A: 
aa=['a','b','c']
=> ["a", "b", "c"]    #Anyone explain Why it became double quote here??

aa.map {|x| [x,aa.index(x)]}   #assume no duplicate element in array
=> [["a", 0], ["b", 1], ["c", 2]]

Hash[*aa.map {|x| [x,aa.index(x)]}.flatten]
=> {"a"=>0, "b"=>1, "c"=>2}
pierr