Conditionals
In any programming language, it is seen that the most common control structure is conditionals.
Conditionals are nothing but the way of telling computers to handle code conditionally: to satisfy some conditions.
Ruby has abundance of conditionals. We are going to discuss some of them below.
-
if: if is the most straightforward conditional.
Syntax:
if expression
#code
end
-
else: else may be included in the if statement to specify the code to be executed if the conditions are not true.
Syntax:
if expression
code
else
code
end
-
elsif: Whenever we want to test multiple conditions, we can add multiple elsif clause between if and else. elsif is a shortened form of “else if”.
Syntax:
if expression1
code1
elsif expression2
code2
.
.
elsif expressionN
codeN
else
code
end
-
?: operator: The conditional operator ?:, acts similar to an if statement, in which ? is replaced with “then” and : is replaced with “else”.
-
case: case in conditional is a multiway statement. It returns the value similar to if the statement does.
Syntax:
case
when x == 1
"one"
when x == 2
"two"
when x == 3
"three"
end
Loops
Ruby provides different types of loops, such as:
-
for a loop - The for/in loop iterates through the elements of an enumerable object (such as an array). Each iteration assigns an element to a specified loop variable and executes the loop's body. for loop is preferred when we know the number of times loop statements are executed.
-
while loop - In a while loop, The condition to be tested is given at the beginning of the loop, and the loop executes the statements until the condition is satisfied. When the condition becomes false, the control goes out. while loop is used when the execution of the statement is not fixed in a program.
-
do-while loop - A do-while loop is similar to a while loop. The only difference is that it checks the condition at last. Therefore even if the condition is false, the loop executes the statements at least once.
- until loop - Until the loop executes the statements until the condition is true, it is the opposite of the while loop as the while loop executes the statements until the condition is false.
Iterators and Enumerable objects
Although loops constitute a significant part of the Ruby language for defining program control structure, it is probably more common to write loops rather than using unique methods called iterators.
- Iterators in ruby are one of the most noteworthy features of Ruby which help us in defining the control structure of ruby.
- We use the term iterator to mean any yield statement method.
- They do not serve the purpose of an iteration or looping function.
For example, data structures like Array, Hash, Range, and several other classes define each iterator that passes each collection element to the associated block.
Similarly, an Enumerable object is one whose purpose is to enumerate over some other object.
Now that you got a brief understanding of iterators and enumerable objects in ruby, let's get to the main discussion.
Iterators in Ruby
Iterators are one of the most remarkable features of Ruby. Each map, upto, and times are all iterators and interact with the block of code. Yield is behind the complex control structure. The Iterator simply means to do one thing multiple times. Sometimes iterators are also known as custom loops.
Iterators are the object-oriented terminology in Ruby, or we can say iterators are the methods supported by collections such as Array, Hashes, etc. Iterators in ruby return all the elements of the collection one by one.
Types of iterators present in Ruby are:
- Each Iterator
- Times Iterator
- Upto Iterator
- Step Iterator
- Downto Iterator
-
Each_Line Iterator
Let us discuss them one by one:
1.Each Iterator
Each Iterator returns all the elements from an array or hash. This iterator returns values one by one.
Syntax:
collection.each do |variable_name|
# code to be iterate
end
Example:
(1...6).each do |i|
puts i
end
Output:
1
2
3
4
5
2. Times Iterator
In Times Iterator, a loop is embedded a certain number of times. The Loop is started with zero and is executed until one less than the specified number.
Syntax:
t.times do |variable_name|
# code to be executed
end
Example:
5.times do |i|
puts i
end
Output:
0
1
2
3
4
3. Upto Iterator
Upto Iterator is known to be following the top to bottom approach. It contains both the top and bottom variables in the iteration.
Syntax:
top.upto(bottom) do |variable_name|
# code to execute
end
Example:
2.upto(6) do |n|
puts n
end
6.upto(2) do |n| # here top > bottom # so no output
puts n
end
Output:
2
3
4
5
6
4. Downto Iterator
This Iterator is opposite to the Upto Iterator. In this Iterator, we follow the bottom-to-top approach.
Syntax:
top.downto(bottom) do |variable_name|
# code to execute
end
Example:
6.downto(2) do |n|
puts n
end
2.downto(6) do |n| # here top < bottom # so no output
puts n
end
Output:
6
5
4
3
2
5. Step Iterator
This Iterator is used to iterate in the step where we have to skip a specified range.
Syntax:
Collection.step(rng) do |variable_name|
# code to be executed
end
Example:
(0..30).step(5) do|i|
puts i
end
Output:
0
5
10
15
20
25
30
6. Each_Line Iterator
This iterator is used to iterate a new line in the given string.
Syntax:
string.each_line do |variable_name|
# code to be executed
end
Example:
"Welcome\nto\nCoding Ninjas".each_line do|i|
puts i
end
Output:
Welcome
to
Coding Ninjas
Internal Iterator Vs External Iterators
We will now learn what Internal Iterator and external Iterator are. The core issue here is to decide which party controls the iteration, the Iterator or the user that uses the Iterator.
Whenever the user handles the iteration, the Iterator is known as External Iterator, and whenever the Iterator controls the iteration, the Iterator is known as Internal Iterator.
Users that use an external iterator need to advance the traversal and request the next item explicitly from the Iterator.
On contrary, in the internal Iterator, the user handover an operator to perform to the internal Iterator, and according to the requirements, the Iterator applies that operation to every item. External iterators are more flexible compared to internal iterators.
Iterators and concurrent Modification
Now, we will understand what iterators and concurrent modifications is with some examples.
In Ruby, its core collection of classes iterate over live objects instead of private copies of those objects; also, they make no effort to detect or prevent concurrent Modification to the collection while its iterated.
For example, if you call each method, and block related with that invocation calls the shift method for the same array, the output of the iteration may ve overwhelming:
a = [1,2,3,4,5]
a.each {|x| puts "#{x},#{a.shift}" } # prints "1,1\n3,2\n5,3"
Output:
1,1
3,2
5,3
We may see similar behavior if one thread modifies a collection while the other thread is iterating it. The solution to avoid this is to make a copy of the collection before iterating it.
For example, below code adds a method each_in_snapshot to the Enumerable module:
module Enumerable
def each_in_snapshot &block
snapshot = self.dup
snapshot.each &block
end
end
So, I hope you understand the concept of iterators and concurrent modifications.
Frequently Asked Questions
When do we get the ConcurrentModification exception while using an iterator?
The Iterator will throw this ConcurrentModificationException if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator.
What are iterators in Ruby?
Iterators are the object-oriented concept in Ruby. In simple words, iterators are the methods that are supported by collections(Arrays, Hashes, etc.).
What is Loop in ruby?
Loops in Ruby are used to implement the same block of code a specified number of times.
What is Each_with_Index in ruby?
The each_with_index function in Ruby is used to Iterate over the object with its index and returns the value of the given object.
What are data types in ruby?
Different types of data types present in ruby are Boolean, Number, String, hashes, Array, Symbols, etc.
Conclusion
In this article, we discussed Iterators and concurrent Modification in ruby in detail with the help of an example. We started with the basic introduction of ruby, then we saw what iterators are in ruby, and then we saw the concept of iterators and concurrent Modification.
If you want to learn more about such topics, you can see Introduction to ruby on rails, Directory Structure in Ruby, Ruby on Rails, and Ruby vs. Python. Also, refer to the Official Documentation and Ruby Koans. You can explore some more articles on For Loop in Ruby, Operators in Ruby, or directly access the Coding Ninjas Studio for our courses.
You can also refer to our guided path on Coding Ninjas Studio to upskill yourself in Data structure and algorithms, Competitive Programming, Javascript, and System Design. Do upvote our blogs if you find them helpful and engaging!
Happy learning!
