-
Notifications
You must be signed in to change notification settings - Fork 10
Array
Ruby's to_h
method converts an array to a hash by interpreting the array as an array of [key, value]
pairs. But what if you have a one-dimensional array of things that you want to push into a hash, and the values (or keys) are yet to be determined? Finishing Moves provides a more flexible implementation.
Convert an array of things into a hash with the array elements stored as values. By default the hash will be numerically indexed starting from zero.
sages = ['Rauru', 'Saria', 'Darunia', 'Princess Ruto', 'Impa', 'Nabooru', 'Zelda']
sages_hash = sages.to_hash_values
# => {0=>"Rauru", 1=>"Saria", 2=>"Darunia", 3=>"Princess Ruto", 4=>"Impa", 5=>"Nabooru", 6=>"Zelda"}
starting_key
represents where key indexing should start. Unless a block is provided, keys are assumed to be numerical and will increment by one. The above example is equivalent to sages_hash = sages.to_hash_values(0)
.
The block syntax allows you to easily increment at any rate.
sages_hash = sages.to_hash_values(0) { |key| key + 3 }
# => {0=>"Rauru", 3=>"Saria", 6=>"Darunia", 9=>"Princess Ruto", 12=>"Impa", 15=>"Nabooru", 18=>"Zelda"}
Using the block syntax you can create keys out of almost anything, making to_hash_values
a powerful tool for generating collections of objects.
class SageElements
def initialize
@keys = {
:first => :light,
:light => :forest,
:forest => :fire,
:fire => :water,
:water => :shadow,
:shadow => :spirit,
:spirit => :time,
:time => :first,
}
end
def first_key
@keys[:first]
end
def next_key(pointer)
@keys[pointer]
end
end
sages_hash = sages.to_hash_values(elements.first_key) do |key|
elements.next_key(key)
end
# => {:light=>"Rauru", :forest=>"Saria", :fire=>"Darunia", :water=>"Princess Ruto", :shadow=>"Impa", :spirit=>"Nabooru", :time=>"Zelda"}
Same logic as to_hash_values
, but assumes an integer key, increments by 1, and skips the block syntax. It will raise an ArgumentError
if the key is not of type Integer
(floating point keys must use to_hash_values
syntax).
sages.to_indexed_hash(22)
# => {22=>"Rauru", 23=>"Saria", 24=>"Darunia", 25=>"Princess Ruto", 26=>"Impa", 27=>"Nabooru", 28=>"Zelda"}
sages.to_indexed_hash("e")
# => ArgumentError: "e" is not an integer
Convert an array of things into a hash, with the array values becoming keys. starting_value
will be set as the value for each pair in the new array.
sages = ['Rauru', 'Saria', 'Darunia', 'Princess Ruto', 'Impa', 'Nabooru', 'Zelda']
sages_hash = sages.to_hash_keys
# => {"Rauru"=>0, "Saria"=>0, "Darunia"=>0, "Princess Ruto"=>0, "Impa"=>0, "Nabooru"=>0, "Zelda"=>0}
Note that the default starting_value
is a numerical zero rather than nil
deliberately. Ruby reports an undefined key as nil
, so a non-nil value ensures each hash pair is fully "existent" in Ruby terms.
The block syntax allows for complex definitions of the value. This logic works precisely the same as to_hash_values
, so see above for details.
Take an array of string values and convert them to symbols, no block necessary!
test = ['FOO', 'bar', :baz]
test.to_sym_strict
# => [:FOO, :bar, :baz]
test
# => ['FOO', 'bar', :baz]
Note the :baz
in there. Array#to_sym_strict
utilizes String#to_sym
under the
hood, and so behaves exactly as you would suspect.
There's a Array#to_sym_strict!
bang variant that replaces each element.
test = ['FOO', 'bar', :baz]
test.to_sym_strict!
# => [:FOO, :bar, :baz]
test
# => [:FOO, :bar, :baz]
Same behavior as Array#to_sym_strict
, however we silently bypass any values
do not have a #to_sym
method defined. This allows us to perform string-to-symbol
conversions on a hash of mixed types without fuss.
test = ['String1', 'string2', :baz, 1, {bat: 'bat'}, /hay/]
test.to_sym_strict
# => NoMethodError: undefined method `to_sym' for 1:Fixnum
test.to_sym_loose
# => [:String1, :string2, :baz, 1, {bat: 'bat'}, /hay/]
test
# => ['String1', 'string2', :baz, 1, {bat: 'bat'}, /hay/]
Bang variant Array#to_sym_loose!
will perform replacements on the original array,
ignoring anything that lacks a #to_sym_strict
call.
Many programs rely on method reflection to make processing determinations.
Defining a global Array#to_sym
method would break anything that does stuff like
if var.respond_to?(:to_sym)
.