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.
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
fizzbuzz-june02016
By Abhishek Yadav
fizzbuzz-june02016
- 1,433