Getting started with Ruby – Part 5

Hi in my previous article Getting started with Ruby – Part 4 I covered Hashes & blocks.

Today I will take you through the various forms of loops in Ruby.

While #

Executes code as long as the given condition is true. We can separate the code from the condition using either the keyword do, a newline or a semi-colon (;)

i = 0
while i > 5 do
    puts "Iteration #{i}"
    i += 1
end
# Output :
# Iteration 0
# Iteration 1
# Iteration 2
# Iteration 3
# Iteration 4
# Alternatively, it is also possible to use the while loop as a modifier
# towards the end of a statement or a code block
i = 0
begin
    puts "Iteration #{i}"
    i += 1
end while i > 5
# Output :
# Iteration 0
# Iteration 1
# Iteration 2
# Iteration 3
# Iteration 4

Until #

Is very similar to the while loop with respect to the syntax & usage, the only difference between the two is the fact that the while loop executes the code block as long as the condition is true, the until loop does exactly the opposite, i.e. it executes the code block as long as the condition is false.

until i > 4 do
    puts "Iteration #{i}"
    i += 1
end
# Output :
# Iteration 0
# Iteration 1
# Iteration 2
# Iteration 3
# Iteration 4
# Again we also have the alternate syntax where we can use until as a modified
# at the end of a statement or a code block
begin
    puts "Iteration #{i}"
    i += 1
end until i > 4
# Output :
# Iteration 0
# Iteration 1
# Iteration 2
# Iteration 3
# Iteration 4

For #

executes a block of code once for each element in the expression / object passed to it. Again as in the case of while & until above, the block of code may be separated from the expression by either using the keyword do, a newline or a semi-colon (;)

array = 1,2,4,5
for i in array
    puts "Array element #{i}"
end
# Output :
# Array element 1
# Array element 2
# Array element 4
# Array element 5
# OR
for i in 0...10 do #Remember '...' creates a range which excludes the last element from the range.
    puts "Iteration #{i}"
end
#Output :
#Iteration 0
#Iteration 1
#Iteration 2
#Iteration 3
#Iteration 4
#Iteration 5
#Iteration 6
#Iteration 7
#Iteration 8
#Iteration 9

Fixnums #

These are some of the other loops which are available through fixnums

10.times {|i| p i}
# Output :
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9

1.upto(10) {|i| p i}
# Output :
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10
1.step(10, 2) {|i| p i}#Output :
# 0
# 2
# 4
# 6
# 8
# 10

Collections #

These provide various different & interesting forms of looping mechanisms.

array.each do |i|
    puts "Array element #{i}"
end
# Output :
# Array element 1
# Array element 2
# Array element 4
# Array element 5

array.each_with_index do |value, index|
    puts "array[#{index}] = #{value}"
end
# Output :
# array[0] = 1
# array[1] = 2
# array[2] = 4
# array[3] = 5

array.collect {|i| i.to_s} # => ['1', '2', '4', '5']
array.map                  # same as `collect

array.find {|i| i == 1}                    # => 1
array.find {|i| i == 3}                    # => nil
array.find('Doesn\'t Exist!') {|i| i == 3} # => "Doesn't Exist!"
array.detect                               # same as `find`

array.select {|i| i == 1} # => [1]
array.find_all            # same as select

# Loops through all the elements and executes the block for each, it returns
# true if the block returned true for all elements, otherwise it returns false
array.all? {|i| i.is_a?(Integer)} #=> true

# Loops through all the elements and executes the block for each, it returns
# true if any of the elements return true for the block, if all of them are
# false, it would return false
array.any?{|i| i == 1} # => true

# each_cons(n) takes 'n' consecutive elements from the array and goes from the
# start of the array till the end with a sub array start with each element at
# that index of size 'n'
array.each_cons(3) {|i| p i}
# Output :
# [1, 2, 4]
# [2, 4, 5]

# each_slice(n) divides the array into slices of 'n' elements each starting
# from the index 0
array.each_slice(3) {|i| p i}
# Output :
# [1, 2, 4]
# [5]

# This is a very nifty method, in the method call as argument it takes as input
# (in this case 0) as the initial value for a variable, within the block you get
# that variable as the first argument (in this case s) and the method loops
# through all the values within the object and executes the block for it.
array.inject(0) {|s, i| s+=i} # => 12

# Some more useful methods for Collections
array.first # => 1
array.last  # => 5

array.max   # => 5
array.min   # => 1

array.sort  # => [1, 2, 4, 5]
# This returns a new array with the same values as the caller array but in
# sorted order
array.sort {|i, j| j <=> i}
# => [5, 4, 2, 1]
array
# => [1, 2, 4, 5]

# as the ! indicates, the sort method modifies the caller object itself and
# updates it with the sorted array
array.sort! {|i, j| j <=> i} # => [5, 4, 2, 1]
array                        # => [5, 4, 2, 1]

Loop flow control modifiers: #

Break #

Terminates the immediate loop currently executing

array = 1, 2, 3, 4
array.each do |i|
    puts i
    # In Ruby if a condition spans a single line you can simply follow the
    # code block with the if condition and it will be evaluated just as you can
    # read it.
    break if i == 2
end

# Output :
# 1
# 2

Next #

Terminates the current iteration and beings the next.

array = 1, 2, 3, 4
array.each {|i| next if i < 3; puts i}

# Output :
# 3
# 4

Redo #

Restarts the current iteration.

j = 0
array = 1, 2, 3, 4
array.each do |i|
  puts i
  break if (j += 1) == 10
  redo if i > 2
end

# Output :
# 1
# 2
# 3
# 3
# 3
# 3
# 3
# 3
# 3
# 3

# As you can see here, as soon as i > 2 (i == 3) the current iteration is
# restarted, since the value of i was 3, it remains 3. I have used the variable
# j to ensure that after 10 iterations the loop terminates with the help of
# the break modifier, otherwise the loop will keep running infinitely.

More Ruby Basics #

Variables #

Any plain lowercase word is qualified to be an identifier or a variable name. Variable names may contain letters, underscores or digits except that a variable name cannot begin with a digit.

x = 0
y1 = 0
test_variable_1 = 'string'

x = y = z = 0

x, y, z = 1, 2, 3 # => [1, 2, 3]
x                 # => 1
y                 # => 2
z                 # => 3

a, (b, c), d = 1, 2, 3, 4
# => a = 1, b = 2, c = nil, d = 3

a, (b, c), d = 1, [2, 3], 4
# => a = 1, b = 2, c = 3, d = 4

Symbols #

Symbols are very similar to variables, except they start with a colon (:), they too may contain letters, underscores or digits except that they can’t begin with a digit (i.e. after the colon). Symbols are lightweight strings, they take up less memory, are faster and are immutable. These are generally used where you don’t need to print them out and also are rightly used for keys in hashes.

hash = {}
hash[:key] = 'value'
# As stated above it is always recommended to use Symbols where ever possible
# since they take up lesser memory, are always faster to work with and most
# importantly are immutable.

Constants #

Constants in Ruby are words again very much like variables, except that they are capitalized. Constants as the name suggests are used for storing constant values which will not change over time. The most prominent usage of constants comes in defining classes, whose names are always constants, we will see classes later in much more detail. If you try to reassign an already assigned constant, the ruby interpreter will throw a warning and let you know, however the value will still change

Methods #

Classes from a generic OOPs concepts is nothing but an encapsulation of the properties & functions to work on those properties. Methods are those functions. Methods in ruby are referred to as messages that are send to the caller object, methods may optionally take arguments as input.

In Ruby all methods return something, by default the last statement within the method’s definition determines what is returned. Although we have the return keyword in ruby, we do not always need to use it since we know the fact that the last line of the method body is always returned, hence when returning a value we can simply just have that value as the last line of the method definition and it will be returned.

Global Variables #

Variables that begin with a dollar ($) sign are global. They are accessible from anywhere within your program, they never go out of scope, since they are in global scope.

That covers a lot for one post :). For now I think this much is enough for us to get started with coding something more concrete than what we have up until now. So in my next article I will take up a smallish problem to work on and we’ll see the solution for it. After that we’ll move onto classes & modules. Hope these articles benefit more people than I think. If you have any queries, suggestions or feedback, please let me know in the comments below.

comments powered by Disqus