FizzBuzz

Ruby programming Workshop

4 June 2016

Agenda

  • Basics
  • Looping
  • File-IO
  • String & Array
  • Conclusion

1-Basics

Hello World

Basics

Ruby is an interpreted programming language.

We write a program, and execute it from its source. There is no separate compilation step.

 

Hello World

Basics

Create a file called hello.rb

Add the following code:

    puts "Hello world"
    ruby hello.rb

Save it,
Execute it from the command line:
 

Variables

Basics

  • Ruby is a dynamically typed language.
  • Variables don't need to be declared with their data-type.
  • Variables assume the type of their data.

Variables

Basics

## Example:

     a = 2
     b = 3
     c = a + b
     puts c

Printing values

Basics

We use puts to print values to the standard output.

## Example:

   a = "Hello Abhishek"
   puts a
   puts a, "How are you?"

Branching

Basics

Branching is done using the if statement.

    if <condition>
      # do something
    end

 

If the condition gives a true value, the code within the if block is executed. There is also an else:

    if <condition>
      # do this
    else
      # do that
    end

Branching

Basics

## Example:

    a = 2
    if a > 0
      puts "Positive"
    else
      puts "Negative"
    end

Methods

Basics

To group code that can be executed later, we use methods
A method can be defined with def keyword.

 

Methods are invoked from their names - placing parenthesis is optional.
 

The result of the last line is returned from a method

Methods

Basics

## Example:

    def hello(a)
      puts a
    end

    hello a
    hello(a)  # same 

IRB

Basics

  • IRB (Interactive Ruby) is a command line console for Ruby.
  • We can execute live code on IRB.
  • IRB is useful in debugging and experimenting

IRB

Basics

- Type irb in the shell
- It will show a prompt like this:

 

    irb(main):001:0>

 

- Now type all the above examples line by line on it:

IRB

Basics

## In IRB:

    puts "hello world"


    a = 2
    b = 3
    c = a + b
    puts c


    def hello
      puts "hello world"
    end


    hello

2-Loops

Iterators

Loops

Loops are used when we need to execute something again and again.
Looping in Ruby is very different from C or Javascript.
We mainly use iterators

# Example:

    5.times{ puts "hello world" }

The times method here is an iterator, and the code between the curly braces is a block. We are actually passing the block to the iterator.

(More on this later.)

each

Loops

The each iterator is available on array like objects.
It iterates through the array, and executes the block for each element.

In other words, the code between the curly-braces is executed again and again.

 

 

 

 

 

The above code loops through the array arr, and prints squares of all the numbers. And each time, it maintains the iterated value in the variable i.

The variable i here is the so called 'block argument'

    arr = [1, 2, 3, 4]

    arr.each{ |i|
      square = i ** 2
      puts square
    }

loop

Loops

loop gives us an infinite loop.

We'll have to set-up break and increments on our own.

The following is an equivalent of a for loop in C :

 


    c = 0
    loop {

      puts "hello"
      c += 1               # Increament like this. There's no ++ in Ruby
      break if c >= 10     # Single line if is allowed

    }

loop

Loops

loop is more useful when we don't know the size of the input.

 

    loop{

      input = gets
      input = input.chomp  # Used to remote the \n at last
      break if z == ""
      puts input

    }

while

Loops

Similar to the while loop in c:

    c = 0
    while c < 10

      puts "hello"
      c += 1

    end

Range

Loops

Range is a data structure similar to Array.
We can express a continuous list neatly using a range.

 

    1..5      # Range of number 1 to 5: 1,2,3,4,5
    'a'..'z'  # Range of characters a to z

    (1..5).to_a  # => [1,2,3,4,5]

Ranges can be converted to arrays using `to_a` method

Both the starting and ending values are included in a range

3-File-IO

ARGV

File-IO

ARGV is an array that holds the arguments passed while the ruby program is invoked from command line.

# Example: sample.rb

    puts ARGV
    ruby sample.rb hello 12  #prints hello 12

Execute:

 

 

The program name and ruby are not counted

Reading files

File-IO

Read as a big string:

    str = File.read("sample")

Read as lines (most useful):

    # lines = array of lines, separated by \n
    lines = File.readlines("sample")  
    lines.each do |line|
      ## My code
    end

Reading files

File-IO

Open the file and read line by line:
(use when files are big)

    File.open("sample", "r") do |f|
      f.each_line do |line|
        ## My code
      end
    end

ARGF

File-IO

ARGF is the file descriptor of the standard input.
To read from standard input, we can use:

 

 

 

This will block the program until STDIN comes up with something

    ARGF.read

4-Array-String

String

Array-String

Strings are independent data structures in Ruby - not like C where a string is treated as a list of characters.

 

 

 

Several methods for manipulations are provided by the standard library.

 

Documentation: String class

   str = "abc"
   str = 'xyz'  # both same

String: splitting

Array-String

Splitting strings:

Using split method, we get an array of parts:

We can also get a list of all characters:

   str = "/home/user/code/sample.rb"

   str.split("/") #=> ["", "home", "user", "code", "sample.rb"]
    str = "abc"
    str.chars   #=> ["a", "b", "c"]

String: join/concat

Array-String

Joining/concatenating strings:

Using the join method, we can join an array of using a separator:

We can also concatenate using +

   arr = ["", "home", "user", "code", "sample.rb"]

   arr.join("/")  #=> "/home/user/code/sample.rb"
   str1 = "Hello"
   str2 = "World"
   str3 = str1 + str2 #=> "HelloWorld"

String: interpolation

Array-String

We can insert a string within another one using interpolation:

We can interpolate numbers and other types of objects too:

   name = "John"
   str = "Hello #{name}"  #=> "Hello John"
   puts str
   num = 3
   str = "There were #{num} errors" #=> "There were 3 errors"
   puts str

String: indexed access

Array-String

We can read a string as if it were an array of characters:

    str = "abcdef"
    str[0]        # => "a"
    str[1]        # => "b"
    str[1..3]     # => "bcd"
    str[0..-2]    # => "abcde"   # negative indexes count backwards

String

Array-String

Other useful methods


"abc".length       #=> 3  # length

"abc".upcase       #=> "ABC" # upcase
"ABC".downcase     #=> "abc" # downcase
"abc".capitalize   #=> "Abc" # capitalize


"abc".reverse     #=> "cba" # reverse
"abc\n".chomp     #=> "abc" # chomp: removes \n from last if present
"abc" == "abc"    #=> true  # comparison


"hello world".gsub(" ", "-")  #=> "hello-world" #Substitution

String

Array-String

Note that most of these methods don't perform in-place changes.
The original string is left unchanged, and a new string is returned with the changes.

Array

Array-String

Array is a collection of objects. Objects can be related or unrelated.
Arrays are ordered and indexed.

    arr = [1, "2", "hello", {"key" => "value"}, 1..5 ]  # a valid array

Array: addition

Array-String

Adding to array:

Using <<

    arr = [1,2,3]
    arr << 4      #=> [1, 2, 3, 4]

Using push

    arr = [1,2,3]
    arr.push(4)   #=> [1, 2, 3, 4]

Array: access

Array-String

Accessing from Array:

Using index :

    arr = [1, 2, 3, 4]
    arr[0]               #=> 1
    arr[-1]              #=> 4
    arr[1..2]            #=> [2, 3]
    arr[100]             #=> nil

Get the first few:

    arr.take(2)        #=> [1, 2]

Array: find/search

Array-String

We can use the index method to get the index of an element

Or use detect method to get an element that matches a criteria

    arr = [1, 2, 3, 4]
    arr.index(3)              # => 1
    arr.detect{ |x| x > 3 }   # => 4
    arr.bsearch{ |x| x == 2 } # => 2  # uses binary search

Array: filtering

Array-String

select method gets a sub array based on some condition:

    arr = [10, 20, 30, 40]
    arr.select{ |x| x > 25 }  #=> [30, 40]

Array: sorting

Array-String

Sorting is available within the library.
Implements the quick-sort algorithm, which generally quite efficient.

    arr = [3, 10, 52, 0]
    arr.sort                 # [0, 3, 10, 52] # gives sorted array

Using sort_by we can also sort on a property instead of the value:

    arr = [-2, 10, -33, 20]
    arr.sort_by{|x| x.abs }     # [2, 10, 20, 33]

Array: map

Array-String

If we need to transform the array to a different list using same logic on all elements, we can use `map`. For example -

# We can get squares of all elements:

     arr = [1, 2, 3, 4]
     arr.map{ |x|  x**2 }   #=> [1, 4, 9, 16]


# Or increament every value by 1

    arr = [1, 2, 3, 4]
    arr.map{ |x| x+1 }      #=> [2, 5, 10, 17]


# Or we can convert string list to integers

    arr = ['20', '30', '44']
    arr.map{ |x| x.to_i  }   #=> [20, 30, 44]  # to_i: string to integer

Array

Array-String

#size:    
[1, 2, 3].size       #=> 3

#reverse: 
[1, 2, 3].reverse    #=> [3, 2, 1]

#join:    
[1, 2, 3].join("-")  #=> "1-2-3"

#max:     
[1, 2, 3].max        #=> 3 

#uniq:    
[1, 1, 2, 3].uniq    #=> [1, 2, 3]

#compact: 
[1, nil, 2].compact  #=> [1, 2]

Other useful methods

5-Conclusion

Space and time complexity

Conclusion

  • Space and time complexity is a measure of how efficient our algorithm is.
  • Time complexity is expressed in the Big-O notation
  • We say an algorithm is O(n^2) if the time taken is proportional to the square of the size of input

Time complexity

Conclusion

O(n^2) example:

    # Hypothetical: O(n^2)

    lines = File.readlines(ARGV[0])
    arr = lines.map{ |line| line.chomp.chars }   # Its a square matrix
    n = arr.size
    n1 = n - 1
    
    (0..n1).each do |i|
      (0..n1).each do |j|

        x = arr[i][j]
        puts "Its: (#{i},#{j})  #{x}"

      end
    end 

Time complexity

Conclusion

O(n^2) example:


    # Selection sort: O(n^2)

    arr = File.read(ARGV[0]).split(",")
    n = arr.size
    
    n.times do |start|
      min = start  
      start.upto(n-1) do |i|  
        min = i if arr[i] < arr[min]
      end  
      arr[start], arr[min] = arr[min], arr[start]  # swap
    end 

Time complexity

Conclusion

  • O(n^2) is not a good time-complexity
  • Time complexity can vary across data sets too
  • A general rule of thumb: variable sized nested loops can be increasing time complexity
  • Also, for many operations, better time complexity is achieved by compromising on space (eg: hashing, indexing)
  • Keep an eye on complexity while implementing. Interviewers also like the subject

What next

Conclusion

  • Ruby programming:
    • ​Codeacademy Ruby course: https://www.codecademy.com/learn/ruby
    • Learn about Hash, and blocks
    • Implement a gem
  • Programming puzzles:
    • https://www.codeeval.com
    • https://codility.com
    • https://www.hackerrank.com
    • https://projecteuler.net

What next

Conclusion

  • Join Chennai-Ruby
    • Join on Slack: http://chennai-ruby.org
    • Join on Meetup: http://www.meetup.com/chennai-ruby
    • Follow on Twitter: http://twitter.com/chennairb
    • And give a talk sometime

Thank you

Copy of fizzbuzz-june02016

By Abhishek Yadav

Copy of fizzbuzz-june02016

  • 1,241