Arrays & Hashes

Ruby Arrays

An array is an ordered collection of objects; they can be of any type and you can intermix different types inside a particular array. To create an array use square brackets - below, we're instantiating an array containing an integer, a string and a float:

an_array = [1, 'two', 3.0]

Element indexes

Just like in other programming languages, arrays in Ruby are 0-indexed - belowe we're printing the second element of the array:

an_array[1]
  two

Requesting an index that doesn't exist will return a nil value:

an_array[3]
  nil

Indexes can also be negative and they are used to transverse the array in a reverse order:

an_array[-1]
  3.0
an_array[-3]
  1

Array slices

You can return a part (or slice) of an array by providing a range with the start and end index:

letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
letters[2..5]
  c
  d
  e
  f

NB:Ranges are a basic Ruby type.

To retrieve a slice containing the elements from a certain index, don't specify an end index:

letters[5..]
  f
  g
  h
  i
  j

Basic array methods

Using the letters arrays above, let's apply some methods to it - we'll start with its length:

letters.length
  10

NB:2 aliasses are available for length - size and count will work just as well.

Ruby methods are named in a very intuitive way following the principle of least suprise. It should be very easy for you to understand the methods below:

letters.empty?
  false
letters.sort
  ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
letters.reverse
  ["j", "i", "h", "g", "f", "e", "d", "c", "b", "a"]
letters.min
  "a"
letters.max
  "j"

To view all methods available for our array, use the methods method:

letters.methods
  [:to_h, :include?, :&, :*, :+, :-, 
  :at, :fetch, :last, :union, :difference, :intersection, 
  :push, :append, :pop, :shift, :unshift, :each_index, :join, 
  :rotate, :rotate!, :sort!, :sort_by!, :collect!, :map!, 
  :select!, :filter!, :keep_if, :values_at, :delete_at, 
  :delete_if, :reject!, :transpose, :fill, :assoc, :rassoc, 
  :uniq!, :compact, :compact!, :flatten, :flatten!, :shuffle!, 
  :shuffle, :sample, :permutation, :combination, 
  :repeated_permutation, :repeated_combination, :product, 
  :bsearch, :sort, :bsearch_index, :deconstruct, :count, 
  :find_index, :select, :filter, :reject, :collect, :map, 
  :first, :all?, :any?, :one?, :none?, :minmax, :|, 
  :reverse_each, :zip, :take, :take_while, :drop, :<=>, :<<, 
  :cycle, :drop_while, :==, :sum, :uniq, :[], :[]=, :insert, 
  :empty?, :eql?, :index, :rindex, :replace, :clear, :max, 
  :min, :inspect, :length, :size, :each, :reverse, :concat, 
  :prepend, :reverse!, :to_ary, :to_a, :to_s, :pack, :delete, 
  :slice, :slice!, :dig, :hash, :each_slice, :each_cons, 
  :each_with_object, :chunk, :slice_before, :slice_after, 
  :slice_when, :chunk_while, :to_set, :chain, :lazy, :find, 
  :entries, :sort_by, :grep, :grep_v, :detect, :find_all, 
  :filter_map, :flat_map, :collect_concat, :inject, :reduce, 
  :partition, :group_by, :tally, :min_by, :max_by, :minmax_by, 
  :member?, :each_with_index, :each_entry, :dup, :itself, 
  :yield_self, :then, :taint, :tainted?, :untaint, :untrust, 
  :untrusted?, :trust, :frozen?, :methods, :singleton_methods, 
  :protected_methods, :private_methods, :public_methods, 
  :instance_variables, :instance_variable_get, 
  :instance_variable_set, :instance_variable_defined?, 
  :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, 
  :tap, :class, :display, :singleton_class, :clone, 
  :public_send, :method, :public_method, :singleton_method, 
  :define_singleton_method, :extend, :to_enum, :enum_for, 
  :===, :=~, :!~, :nil?, :respond_to?, :freeze, :object_id, 
  :send, :__send__, :!, :!=, :__id__, :equal?, :instance_eval, 
  :instance_exec] 

Ruby Hashes

A hash is an unordered, dictionary-like collection of pairs of keys and values. They can be of any type and you can intermix different types inside a particular hash, as long as all the keys are unique.

To create a hash use curly braces:

frequency = { "a" => 25, "b" => true, 0 => "nope" }

Retrieving values

Values can be retrieved from a hash using the relevant key (this is why the keys must be unique):

frequency["b"]
  true
frequency[0]
  "nope"

If a non-existent key is used, nil is returned:

frequency[1]
  nil

Hashes also have a fetch method that will return the value for an associated key:

frequency.fetch("b")
  true

Adding new values

New values can be added by assigning them to a new key:

frequency["c"] = 25.4
frequency
  {"a"=>25, "b"=>nil, 0=>"nope", "c"=>25.4}

Deleting keys

An existing key can be removed from an array:

frequency.delete("a")
frequency
  {"b"=>true, 0=>"nope", "c"=>25.4}

Using symbols for keys

A very common usage of hashes is with symbols as keys. Since symbols are unique, they are a great candidate for the keys of a hash (which must be unique):

frequency = { :a => 25, :b => true, :c => "nope" }
  {:a=>25, :b=>true, :c=>"nope"}

NB: Given the name restrictions for symbols, :0 won't be a valid symbol name.

In fact, the usage of symbols in hashes is so common, that Ruby provides a shorter syntax for it (notice that the printed value below is identical with the one above):

frequency = { a: 25, b: true, c: "nope" }
  {:a=>25, :b=>true, :c=>"nope"}

Symbols are to be used as keys to retrieve the associated value:

frequency[:a]
  25

Basic array methods

Keys and values can be retrieved as arrays (order not guaranteed):

frequency = { :a => 25, :b => true, :c => "nope" }
frequency.keys
  [:a, :b, :c]
frequency.values
  [25, true, "nope"]

A hash can also be transformed into an array of key,value pairs:

frequency.to_a
  [[:a, 25], [:b, true], [:c, "nope"]]

To find out how many key,value pairs our hash has, you can use a similar method the one for arrays: length. It should be very easy for you to understand what the methods below do:

frequency.length
  3
frequency.empty?
  false
frequency.min
  [:a, 25]
frequency.max
  [:c, "nope"]
frequency.display
  {:a=>25, :b=>true, :c=>"nope"}
frequency.clear
frequency
  {}

To view all methods available for our array, use the methods method:

frequency.methods
  [:value?, :compare_by_identity, :compare_by_identity?, 
  :deconstruct_keys, :any?, :dig, :<=, :>=, :==, :key, :[], :[]=, 
  :empty?, :eql?, :index, :replace, :clear, :to_h, :include?, 
  :inspect, :fetch, :length, :size, :each, :shift, :<, :>, 
  :select!, :filter!, :keep_if, :values_at, :to_hash, :to_proc, 
  :delete_if, :to_a, :to_s, :reject!, :assoc, :rassoc, :compact, 
  :compact!, :flatten, :delete, :default, :rehash, :store, 
  :select, :default=, :default_proc, :default_proc=, :each_value, 
  :each_key, :each_pair, :transform_keys, :transform_keys!, 
  :transform_values, :transform_values!, :keys, :values, 
  :fetch_values, :invert, :slice, :filter, :update, :reject, 
  :merge, :has_key?, :merge!, :hash, :member?, :has_value?, :key?, 
  :each_slice, :each_cons, :each_with_object, :zip, :take, 
  :take_while, :drop, :drop_while, :cycle, :chunk, :slice_before, 
  :slice_after, :slice_when, :chunk_while, :sum, :uniq, :to_set, 
  :chain, :lazy, :max, :min, :find, :entries, :sort, :sort_by, 
  :grep, :grep_v, :count, :detect, :find_index, :find_all, 
  :filter_map, :collect, :map, :flat_map, :collect_concat, 
  :inject, :reduce, :partition, :group_by, :tally, :first, :all?, 
  :one?, :none?, :minmax, :min_by, :max_by, :minmax_by, 
  :each_with_index, :reverse_each, :each_entry, :dup, :itself, 
  :yield_self, :then, :taint, :tainted?, :untaint, :untrust, 
  :untrusted?, :trust, :frozen?, :methods, :singleton_methods, 
  :protected_methods, :private_methods, :public_methods, 
  :instance_variables, :instance_variable_get, 
  :instance_variable_set, :instance_variable_defined?, 
  :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, 
  :tap, :class, :display, :singleton_class, :clone, :public_send, 
  :method, :public_method, :singleton_method, 
  :define_singleton_method, :extend, :to_enum, :enum_for, 
  :<=>, :===, :=~, :!~, :nil?, :respond_to?, :freeze, :object_id, 
  :send, :__send__, :!, :!=, :__id__, :equal?, :instance_eval, 
  :instance_exec]