Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction
2.
Statement and Control Structures
3.
Iterators and Enumerable Objects
4.
Looping Through Multiple Iterables in Parallel
5.
Analysis
6.
Frequently Asked Questions
6.1.
What is Ruby?
6.2.
What are enumerators in ruby?
6.3.
Mention Some of the iterators in Ruby
6.4.
What is an iterator in ruby?
6.5.
How does ruby allow looping through multiple iterables in parallel in ruby?
7.
Conclusion
Last Updated: Mar 27, 2024
Easy

Looping through Multiple Iterables in Parallel in Ruby

Author Abhay Trivedi
0 upvote

Introduction

In our day-to-day life, we make a lot of decisions. Our life is not simple as a program executing sequentially. A sequential program is one where lines of code are executed one after the other without branching or repetition. It’s simple, but any program could rarely be that simpler.

Like in our lives, we make a decision based on a particular condition. We have to identify a way in Ruby of telling the computer to execute some code conditionally: to execute it only if some condition is satisfied/ or execute it until the time condition is satisfied. One such way is an iterator in ruby. We will understand all about an iterator in ruby and see looping through multiple iterables in parallel in ruby in this article. Before that, we will briefly introduce statement and control structures.

Statement and Control Structures

So as we already explained, having a simple program that consists primarily of method invocations and variable assignment is rare. What makes such a program particularly simple is its purely sequential execution. Program is executed one after the other without branching or repetition. It is rare seeing any program for being that simple. An Iterator in ruby tells the computer to do one thing multiple times until some condition is satisfied and follows a control structure.

This image describe types of control structures like conditionals and repetition

PROGRAM CONTROL STRUCTURE

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 and 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. Iterator is a concept of Object-Oriented Programming Language and, in simple terms, often defined as methods supported by collections such as an array, hashes etc. Iterator in ruby returns all the laments one after the other.

Similarly, an Enumerable object is one whose purpose is to enumerate over some other object. Now, after a brief understanding of iterators and enumerable objects in ruby, let's get to the main discussion of how ruby allows Looping through Multiple iterables in parallel. Now down the section, we will be getting to know code implementation and a brief discussion on looping through multiple iterables in parallel.

Looping Through Multiple Iterables in Parallel

We want to traverse multiple iteration methods simultaneously to match the corresponding elements in different arrays. Iteration over arrays is made simpler using The REXML::SyncEnumerator class, defined in the REXML library. Each method yields a series of the array, and each array contains one item from each underlying Enumerable object.

We all know that any object which implements each method can be wrapped in an Enumerator object. Objects help us track where we are in a particular iteration over an entire data structure. Usually, while passing a block into the iterator method, the block passed would get called for every element in the iterator without interruption. It will not run any code that is outside the block and would run till the time iterator is done iterating over it. 

The iterator does allow us to stop the iteration by writing the break statement in the code block. Still, the enumerator also allows us to restart from the broken iteration, which the iterator does allow. We could consider an iterator as a vending machine for candies that will dispense all of its candy in a steady stream once we push the button(a faulty one). But the Enumerator class lets us turn that candy dispenser into one that dispenses only one piece of candy every time we push its button.

Now for looping through multiple iterables in parallel, we should first look into the example below, which will help us understand how an array/collection is wrapped using an enumerator.

So consider an array. 

sample_array = ["Hello1", 1, "Hello2", 2, "Hello3", "Hello4", 3, "Hello5"]
You can also try this code with Online Ruby Compiler
Run Code

 

We want to use the functionality of an enumerator to iterate over an array but not the usual way of iteration here; we want to skip Hello entries.

So if you thought wrapping the list in an enumerator would be sufficient, you are partially wrong. It will print the entire list, including hello values. 

CODE 

sample_array = ["Hello1", 1, "Hello2", 2, "Hello3", "Hello4", 3, "Hello5"]
g = Enumerator.new do |yielder|
    count = 0
    loop do
        yielder.yield sample_array[count]
        count += 1
    end
end
puts g.next  # Hello1
puts g.next  # 1
puts g.next  # Hello2
You can also try this code with Online Ruby Compiler
Run Code

 

OUTPUT

Hello1
1
Hello2

 

We could quickly write an iterator that iterates over the array the way we want it to, but we wanted an enumerator object. So we could wrap the array in an Enumerator or a REXML::SyncEnumerable object. While wrapping the array, we are wrapping the array's each method.

If we could define an appropriate code block and pass it to the Enumerator constructor, we could make a generation object out of any piece of iteration code. The enumerator will then know to call and interrupt that block of code, just as it knows to call and interrupt each when we pass the array into the constructor.

Here is the enumerator that could iterate over the array just the way we want it to 

g = Enumerator.new { |g| my_array.my_iterator { |e| g.yield e } }
g.next # => 1 
g.next  # => 2 
g.next  # => 3
You can also try this code with Online Ruby Compiler
Run Code


Now, look for the below code for implementing our above learning to use interosculate methods that would wrap methods.

CODE

def interosculate(*iteratables)
    generators = iteratables.collect do |x|
        Enumerator.new { |g| x.each { |e| g.yield e } }
    end
    done = false
    until done
        generators.each do |g|
            begin
        if item = g.next
            yield item
            done = false
        end
            rescue StopIteration
                done = true
            end
        end
    end
end

words1 = %w{We Know Ninja}
words2 = %w{Best is Coding All}
interosculate(words1, words2.reverse) { |x| puts x }
You can also try this code with Online Ruby Compiler
Run Code

 

OUTPUT

We 
All
Know
Coding
Ninja
is 
Best
You can also try this code with Online Ruby Compiler
Run Code

 

In the above program, we used an interosculate method that wraps another method. The interosculate method accepts any combination of Enumerable objects and Method objects. It turns each of them into an Enumerator object and loops through all Enumerable objects. Thus able to get one element at a time from each. In the above program, we pass the interosculate method, an array, and a Method object, allowing us to iterate through two arrays in opposite directions.

Analysis

Any object that implements each method can be wrapped in an Enumerator object. If you've used Java, think of an Enumerator as a Java Iterator object. It maintains track of where you are in a particular iteration over a data structure. 

Generally, when we pass a block into an iterator method like "each", that block gets called for every element in the iterator without any interruption. No code outside the block will run until the iterator is done iterating. We can stop the iteration by writing a break statement inside the code block. Still, we can't restart a broken iteration afterwords from the same place unless we use an Enumerator. 

Think of an iterator method as a candy dispenser that pours all its candy in a steady stream once we push the button. The Enumerator class lets us turn that candy dispenser into one that dispenses only one piece of candy every time we push its button. We can carry this new dispenser around and ration your candy more easily. 

Frequently Asked Questions

What is Ruby?

Ruby is an open-source dynamic language with natural and easy-to-read/write syntax. Ruby is a careful balance language and a perfect blend of five different languages.

What are enumerators in ruby?

An enumerator in ruby is a class that allows iterations of both types – external and internal. Internal iteration is when the class in question controls iteration, while external iteration is when the environment or the client controls iteration.

Mention Some of the iterators in Ruby

Iterators in ruby help us in defining the control structure of the program. Each, Times, Upto, Downto, Step, and Each_Line are iterators in ruby.

What is an iterator in ruby?

Iterators in ruby are one of the most noteworthy features of Ruby and help us in defining the control structure of ruby. Iterator in ruby passes each collection element to the associated block.

How does ruby allow looping through multiple iterables in parallel in ruby?

We use an interosculate method for looping through multiple iterables in parallel in ruby. The interosculate method accepts any combination of Enumerable objects and Method objects. It turns each of them into an Enumerator object and loops through all Enumerable objects. Thus able to get one element at a time from each. We then pass the interosculate method, an array, and a Method object, allowing us to iterate through two arrays in opposite directions.

Conclusion

In this article, we have studied Looping through Multiple Iterables in Parallel in Ruby in detail and briefly explored Looping using Multiple Iterables in Parallel with the code implementation. We expect that this article must have helped you enhance your knowledge on the topic of Ruby. Give an upvote to the blog to help other ninjas grow.

Also, visit our Guided Path in  Coding Ninjas Studio to learn about  Ruby. If you are preparing for an interview, visit our Interview Experience Section and interview bundle for placement preparations. Upskill yourself in Ruby on RailsBackend Web TechnologiesHadoopSQL, MongoDB, Data Structures and Algorithms, JavaScript,  System Design, and much more!. Please upvote our blogs if you find them engaging and helpful! I wish you all the best for your future adventures and Happy Coding. 

Useful links: Operational DatabasesNon- relational databasesMongoDBTop-100-SQL-problemsinterview-experienceIntroduction to ruby on railsDirectory Structure in RubyRuby on RailsRuby vs Python. You can also refer to the Official RubyRubyOfficial DocumentationRuby FAQRuby KoansRuby DocWhy Ruby?

Thankyou from Coding Ninjas

Live masterclass