Arrays and Hashes – II

We saw how methods relevant to particular data structure can be obtained from ruby – <object>.methods or <data_structure>.methods. 

>> ohio_cities = ["columbus", "cincinnati", "cleveland"]
=> ["columbus", "cincinnati", "cleveland"]
>> ohio_cities.methods
=> [:inspect, :to_s, :to_a, :to_ary, :frozen?, :==, :eql?, :hash, :[], :[]=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, :<=>, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :shuffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch, :pack, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :lazy, :nil?, :===, :=~, :!~, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :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, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
>> Array.methods
=> [:[], :try_convert, :allocate, :new, :superclass, :freeze, :===, :==, :<=>, :<, :<=, :>, :>=, :to_s, :inspect, :included_modules, :include?, :name, :ancestors, :instance_methods, :public_instance_methods, :protected_instance_methods, :private_instance_methods, :constants, :const_get, :const_set, :const_defined?, :const_missing, :class_variables, :remove_class_variable, :class_variable_get, :class_variable_set, :class_variable_defined?, :public_constant, :private_constant, :module_exec, :class_exec, :module_eval, :class_eval, :method_defined?, :public_method_defined?, :private_method_defined?, :protected_method_defined?, :public_class_method, :private_class_method, :autoload, :autoload?, :instance_method, :public_instance_method, :nil?, :=~, :!~, :eql?, :hash, :class, :singleton_class, :clone, :dup, :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, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Let’s see some of the methods to remove or change members in an array. Method named pop works in an opposite way to push method. It removes last member from an array. So, if I use ohio_cities.pop, “cleveland” will be removed from this array and it’ll have only two members remaining with it.

>> ohio_cities #output ohio_cities array
=> ["columbus", "cincinnati", "cleveland"]
>> ohio_cities.pop
=> "cleveland"
>> ohio_cities #ohio_cities array after pop method usage
=> ["columbus", "cincinnati"]

Similarly, shift method is a complimentary to unshift method we learned before. It removes first member from an array. Companion of insert method is delete_at method. It takes index value of a member that you want to get rid of in an array.

Some other methods that can come handy to you are –

>> fruits = ["apple", "orange", "papaya", "banana", "peach", "plum", "apricot", "pineapple"]
=> ["apple", "orange", "papaya", "banana", "peach", "plum", "apricot", "pineapple"]
>> fruits.delete("orange")
=> "orange"
>> fruits #fruits array after deleting orange
=> ["apple", "papaya", "banana", "peach", "plum", "apricot", "pineapple"]

>> fruits.reverse
=> ["pineapple", "apricot", "plum", "peach", "banana", "papaya", "apple"]

If you have looked carefully to methods applicable to an array, you’ll see two methods that may look similar – reverse and reverse! – while both of these methods reverse array members, one without exclamation mark doesn’t modify an original array & one with “!” modifies original array. So, after using fruits.reverse, if you look at fruits array, it’s still the same

>> fruits
=> ["apple", "papaya", "banana", "peach", "plum", "apricot", "pineapple"]

… and if you used reverse!, fruits array is reversed permanently.

>> fruits.reverse!
=> ["pineapple", "apricot", "plum", "peach", "banana", "papaya", "apple"]
>> fruits
=> ["pineapple", "apricot", "plum", "peach", "banana", "papaya", "apple"]

This is true for all the methods with “!”, they change associated object for good. Exclamation is ruby’s way of telling you to use these methods with caution.

>> fruits.sort
=> ["apple", "apricot", "banana", "papaya", "peach", "pineapple", "plum"]
>> fruits #original array remains unchanged
=> ["pineapple", "apricot", "plum", "peach", "banana", "papaya", "apple"]
>> fruits.sort!
=> ["apple", "apricot", "banana", "papaya", "peach", "pineapple", "plum"]
>> fruits #original array gets changed (sorted)
=> ["apple", "apricot", "banana", "papaya", "peach", "pineapple", "plum"]

>> fruits.empty?
fruits.empty?
=> false

Observe the question mark at the end of the method empty? Ruby has many methods that ends with ? These methods have return type of Boolean. It’s like asking a question to ruby, very intuitive! Here we are asking if fruits array is empty? and ruby replies back loud and clear – NO!

Similarly, let’s ask ruby if banana and mango are included in fruits array or not.

>> fruits.include?("banana")
=> true
>> fruits.include?("mango")
=> false

>> fruits.first #first member of an array
=> "apple"
>> fruits.last #last member of an array
=> "plum"
>> fruits.length #number of elements of an array
=> 7

>> fruits + ["mango"] #adds two arrays to generate third array
=> ["apple", "apricot", "banana", "papaya", "peach", "pineapple", "plum", "mango"]
>> fruits #fruits array remains unchanged
=> ["apple", "apricot", "banana", "papaya", "peach", "pineapple", "plum"]

>> fruits.concat(["mango"]) #adds second array to itself (modifies itself)
=> ["apple", "apricot", "banana", "papaya", "peach", "pineapple", "plum", "mango"]
>> fruits #fruits array has mango now
=> ["apple", "apricot", "banana", "papaya", "peach", "pineapple", "plum", "mango"]

>> [1, 2, 3] == [1, 2, 3] #two same arrays
=> true
>> [1, 2, 3] == [4, 5, 6] #two arrays with same length but different members
=> false
>> [1, 2, 3] == [1, 2, 3, 4] #two arrays with different length
=> false
>> [1, 2, 3] == ["a", "b", "c"] #two arrays with different members
=> false

>> odd = [1, 3, 5, 7, 9, 11]
=> [1, 3, 5, 7, 9, 11]
>> odd.slice(3) #member with index 3
=> 7
>> odd.slice(2, 3) #3 members starting at index 2
=> [5, 7, 9]
>> odd.slice(1..4) #members with index value between 1 and 4, including 1 and 4
=> [3, 5, 7, 9]
>> odd.slice(1...4) #members with index value between 1 and 4, including 1 but not 4
=> [3, 5, 7]

Similarly, another version of slice is slice!, which modifies the original array. There is no explicit reason to use slice method, you can access element by just referring its index value.

>> odd[1...4]
=> [3, 5, 7]
>> odd[1..4]
=> [3, 5, 7, 9]

Here interesting thing to learn is how negative index works with arrays in ruby. Just like first member of an array has index value of 0 and all subsequent members have progressing index values, last member of an array has index value of -1 and negative indices count backwards from the end of an array.

>> odd[-1]
=> 11
>> odd[-4]
=> 5
>> odd[-2..-2]
=> [9]
>> odd[-5..-2]
=> [3, 5, 7, 9]

There are a few array methods that aren’t widely used or not useful in routine programming, but provides powerful influence over a given array. The are some projects where they are actually broadly used. Some of these methods are –

zip, compact, collect, map, uniq, count, <=>, each, inspect

What? You didn’t find any example or explanation of what these methods are? Well, that’s your ‘end of the chapter exercise’! Good Luck!

Arrays and Hashes

So, I taught Arrays and Hashes on last Saturday on June 15, 2013 in ATDD class. This class really went well and it’s nice to see everyone progression in their journey of ATDD.

Ruby’s documentation on Array is at http://ruby-doc.org/core-2.0/Array.html and if you’re looking for documentation in prior versions of Ruby you can find them at – Ruby 1.9.3 (http://www.ruby-doc.org/core-1.9.3/Array.html) and Ruby 1.8.7 (http://ruby-doc.org/core-1.8.7/Array.html)

Arrays in ruby are similar to arrays in other programming languages that you might already know. It has some uniqueness like negative index, multiple data types inside a single array etc. We will learn about it in detail. I first learned arrays in C programming language and since then I never have to learn arrays again. Any programming language I go to, I’ll take on its syntax to create and use arrays and I am done. In ruby, like everything, syntax related to arrays is fairly simple and intuitive. Let’s see how to create arrays in ruby.

In its simplest form, array can be created by listing its members inside square bracket (also called literal constructors). So, an array named numbers with numbers from 1 to 5 can be created by

numbers = [1, 2, 3, 4, 5]

Similarly, an array of months can be created by

months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]

If you’re very much attached to C like me, you’ll notice something very quickly. I didn’t declare data type for these arrays I created. I didn’t say what time of data types these arrays will be containing. I just created an array named months and added all members as strings and ruby just followed my order & didn’t complain at all. I think you know where I am going with this now. As you don’t tell ruby which types of members you want in an array, you can probably include different types of members in a single array. Let’s try doing it and see what happens.

>> hundreds = [100, 100.0, "hundred"]
hundreds = [100, 100.0, "hundred"]
=> [100, 100.0, "hundred"]

Alright, ruby didn’t mind when we included an integer, a floating number and a string inside a single array. Cool! You can include arrays and hashes as members of an array and ruby is cool with it.

You can add keyword Array in front of square bracket and it has the same meaning as far as array declaration is concerned.

>> numbers = Array[1, 2, 3, 4, 5]
numbers = Array[1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]

If simplicity is not your type or you like to use new in every line of declaration, you can go not-so-intuitive way of creating arrays. You can create array my using in-built Array class and initialize it with new.

>> numbers = Array.new(5)
numbers = Array.new(5)
=> [nil, nil, nil, nil, nil]

This has created an array named numbers with 5 members and all members are nil right now. We can assign value to the first member of this array by

>> numbers[0] = 1
numbers[0] = 1
=> 1

Now, if you want to create an array with some default value,

>> ones = Array.new(5, 1)
ones = Array.new(5, 1)
=> [1, 1, 1, 1, 1]

this creates an array named numbers with 5 members and all members are 1.

With all the flexibility ruby provides, it also allows you to add members to arrays without re-sizing. You can add members to an array by using either push or <<. Let’s see an example –

>> programming = ["pascal", "c", "c++", "java"]
programming = ["pascal", "c", "c++", "java"]
=> ["pascal", "c", "c++", "java"]
>> programming.push("ruby")
programming.push("ruby")
=> ["pascal", "c", "c++", "java", "ruby"]

Newest string member “ruby” has been added, actually appended, to array named programming. Let’s add “python” to it now.

>> programming<<"python"
programming<<"python"
=> ["pascal", "c", "c++", "java", "ruby", "python"]

Now, if you learned BASIC before pascal, you would like to add it to this array at the beginning. You can do it by unshift.

>> programming.unshift("BASIC")
programming.unshift("BASIC")
=> ["BASIC", "pascal", "c", "c++", "java", "ruby", "python"]

You can add multiple members with push, << and unshift.

>> ones = ["one", "uno"]
ones = ["one", "uno"]
=> ["one", "uno"]
>> ones<<"un"<<"une"
ones<<"un"<<"une"
=> ["one", "uno", "un", "une"]


>> ones.push("unus", "um")
ones.push("unus", "um")
=> ["one", "uno", "un", "une", "unus", "um"]

>> ones.push("eins").push("un")
ones.push("eins").push("un")
=> ["one", "uno", "un", "une", "unus", "um", "eins", "un"]

>> ones.unshift("ena", "ek")
ones.unshift("ena", "ek")
=> ["ena", "ek", "one", "uno", "un", "une", "unus", "um", "eins", "un"]

How about adding members in the middle of an array or to some other position than first and last? You can do it with array.insert(position_where_insert_is_made, value_to_be_inserted).

>> prime = [7, 11, 13, 17, 31, 37]
prime = [7, 11, 13, 17, 31, 37]
=> [7, 11, 13, 17, 31, 37]
>> prime.insert(4, 19)
prime.insert(4, 19)
=> [7, 11, 13, 17, 19, 31, 37]

Essentially the best way to learn ruby is to try .methods to all the data types you know. So, if we have try prime.methods, we’ll get all the methods that can be applied on arrays. And then try to use some of the methods to get real hands-on pleasure in ruby.

>> prime.methods
prime.methods
=> [:inspect, :to_s, :to_a, :to_ary, :frozen?, :==, :eql?, :hash, :[], :[]=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, :<=>, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :shuffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch, :pack, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :lazy, :nil?, :===, :=~, :!~, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :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, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

If you look at this list, you’ll find that we have already worked on some of these methods listed here.

Hope you have got off to a good start on arrays. More on arrays and then hashes soon!