I am attempting to write a method named my_transform
that takes an array as follows:
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
and displays the items' indexes as follows:
item_to_position = {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
I should be able to execute:
my_transform(items) == item_to_position
and receive true
.
I have contemplated using each_with_index
. Should I begin by saying:
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
hash = Hash[*array]
def my_transform
I have to convert the string to a hash. Any help is appreciated.
You can do this in various ways.
Create an array and convert it to a hash
Until fairly recently, you would use the public class method Hash::[] to convert an array to a hash. It works like this:
or
In Ruby v2.1.0 the methods Array#to_h and Enumerable#to_h were introduced. The first works like this:
Therefore, to use
Hash
orto_h
you must first create the array:or
In the second case we'd use it like this:
Let's first create
arr1
. You are right that you need to use Enumerable#each_with_index. You then need to use Enumerable#to_a to convert each element ofitems
to an array[<color>, index]
.Let's look at this more closely:
enum
, an enumerator, is an instance of the class Enumerator. TheEnumerator
class is one of many classes thatinclude
s theEnumerable
module, of whichto_a
is an instance method. Not only does:convert the enumerator to the desired array, but it is a convenient way to view the elements of any enumerator (which are generally passed to either a block or to another enumerator).
So we can now create the hash:
or
or
Suppose now that we had:
We then obtain:
In building the hash, Ruby first creates the key-value pair
"Aqua"=>0
, which she later overwrites with"Aqua"=>3
and then with"Aqua"=>4
. This is a consequence of the fact that hashes have unique keys.Build the hash from scratch
Now suppose we start with an empty hash:
(same as
h = Hash.new
) and add key-value pairs:We could alternatively write:
or
The Ruby way is skip the step
h = {}
and to useeach_with_index
, as before, together with Enumerator#with_object:The "object" in
with_object
is a hash,with_object
's argument being its initial value, here an empty hash. This object is represented by the block variableh
and is returned after all elements ofitems
have been enumerated (so we don't need a subsequent lineh
to return the hash).Lets look at the steps that are performed here. First, we have
which I discussed earlier. Then Ruby computes
Examine the return value carefully. As you see,
enum1
, likeenum0
, is an enumerator. You might think of it as a "compound enumerator". To see the values ofenum1
that will be passed to the block, you can convert it to an array:As you see,
enum1
has five elements, each an array containing an array and a hash. The elements ofenum1
are passed to the block by Enumerator#each, (which calls Array#each):We can use Enumerator#next to pass each element of
enum1
to the block, and set the block variables to its value. The first is:Notice how
[["Aqua", 0], {}]
is decomposed into its three constituent elements and each block variable is set equal to one of the elements.We can now perform the block calculation:
so now:
Then the second element is passed to the block:
Notice how
h
has been updated. The block calculation is now:and now:
The remaining calculations are performed similarly. After all elements of
enum1
have been enumerated,enum1.each
returnsh
.Most Rubies
This works at least as far back as Ruby 1.9.3.
Ruby >= 2.1.0
If you're running a recent Ruby, you can simplify the above to:
The results will be the same as above, but the Array#to_h method simplifies the code a lot. However, you still need to flatten the array to avoid results like:
You can also try this.
e.g.
I would use
Array#to_h
:Note that
to_h
was introduced in Ruby 2.1Using
to_h
yourmy_transform
method could look like this: