In python I can get an iterator from any iterable with iter(); and then I can call next(my_iter) to get the next element.
Is there any equivalent in ruby/rails?
.to_enum will yield the enumerator. For an example a.to_enum will yield the enumerator and you can iterate it from there like a.to_enum.each{|x| p x}.
Or without loop, you can take the element like
p a.to_enum.next
Without a loop:
words = %w(one two three four five)
my_iter = words.each
puts my_iter.next # one
puts my_iter.next # two
But what is the point of an iterator that isn't in a loop? It's kind of the whole raison d'etre of them...
There are many iterators in Ruby as follows:
Each Iterator
Collect Iterator
Times Iterator
Upto Iterator
Downto Iterator
Step Iterator
Each_Line Iterator
Explaining Types of Iterators
Each Iterator: This iterator returns all the elements of an array or a hash. Each iterator returns each value one by one.
Syntax:
collection.each do |variable_name|
# code to be iterate
continue if condition # equivalent next in python
end
In the above syntax, the collection can be the range, array or hash.
referenced from https://www.geeksforgeeks.org/ruby-types-of-iterators/
Related
I'm working on a mini project for a summer class. I'd like some feedback on the code I have written, especially part 3.
Here's the question:
Create an array called numbers containing the integers 1 - 10 and assign it to a variable.
Create an empty array called even_numbers.
Create a method that iterates over the array. Place all even numbers in the array even_numbers.
Print the array even_numbers.
Here's my code, so far:
numbers = [1,2,3,4,5,6,7,8,9,10]
print numbers[3]
even_numbers.empty?
def even_numbers
numbers.sort!
end
Rather than doing explicit iteration, the best way is likely Array#select thus:
even_numbers = numbers.select { |n| n.even? }
which will run the block given on each element in the array numbers and produce an array containing all elements for which the block returned true.
or an alternative solution following the convention of your problem:
def get_even_numbers(array)
even_num = []
array.each do |n|
even_num << n if n.even?
end
even_num
end
and of course going for the select method is always preferred.
This has been asked before, but I can't find an answer that works. I have the following code:
[[13,14,16,11],[22,23]].each do |key,value|
puts key
end
It should in theory print:
0
1
But instead it prints:
13
22
Why does ruby behave this way?
Why does ruby behave this way?
It's because what actually happens internally, when each and other iterators are used with a block instead of a lambda, is actually closer to this:
do |key, value, *rest|
puts key
end
Consider this code to illustrate:
p = proc do |key,value|
puts key
end
l = lambda do |key,value|
puts key
end
Using the above, the following will set (key, value) to (13, 14) and (22, 23) respectively, and the above-mentioned *rest as [16, 11] in the first case (with rest getting discarded):
[[13,14,16,11],[22,23]].each(&p)
In contrast, the following will spit an argument error, because the lambda (which is similar to a block except when it comes to arity considerations) will receive the full array as an argument (without any *rest as above, since the number of arguments is strictly enforced):
[[13,14,16,11],[22,23]].each(&l) # wrong number of arguments (1 for 2)
To get the index in your case, you'll want each_with_index as highlighted in the other answers.
Related discussions:
Proc.arity vs Lambda.arity
Why does Hash#select and Hash#reject pass a key to a unary block?
You can get what you want with Array's each_index' method which returns the index of the element instead of the element itself. See [Ruby'sArray` documentation]1 for more information.
When you do:
[[13,14,16,11],[22,23]].each do |key,value|
before the first iteration is done it makes an assignment:
key, value = [13,14,16,11]
Such an assignment will result with key being 13 and value being 14. Instead you should use each_with_index do |array, index|. This will change the assignment to:
array, index = [[13,14,16,11], 0]
Which will result with array being [13,14,16,11] and index being 0
You have an array of arrays - known as a two-dimensional array.
In your loop, your "value" variable is assigned to the first array, [13,14,16,11]
When you attempt to puts the "value" variable, it only returns the first element, 13.
Try changing puts value to puts value.to_s which will convert the array to a string.
If you want every value, then add another loop block to your code, to loop through each element within the "value" variable.
[[1,2,3],['a','b','c']].each do |key,value|
value.each do |key2,value2|
puts value2
end
end
I'm going over iteration within multidimensional arrays in Ruby on Codecademy and came across a question I can't seem to find the answer to. So, in their example, they show that a multidimensional array can be iterated using the following code:
things = [[1,2,3], ["red", "blue"]]
things.each do |sub_array|
sub_array.each do |item|
puts item
end
end
This prints out the values of both sub_arrays. However, if I only want to display one sub_array, how would I go about that? I have tried the following code but I'm getting an undefined method `each' for 2:Fixnum error.
things = [[1,2,3], ["red", "blue"]]
things.each do |numbers, colors|
colors.each { |item| puts item }
end
So, I guess my question is why my code is not functioning correctly and how I would go about printing out only the array at index 1?
Your block parameters deconstruct the array as follows:
The enumerator generated by :each yields each element of the outer array in sequence, and then applies the pattern matching based on the structure of the block parameters. So in the first iteration, you have [1,2,3] yielded to the block, which is then mapped to numbers = 1 and colors = 2. 3 is ignored because it doesn't fit the pattern.
If you only want to display one sub-array, you don't need iterate over the whole array- just grab the required element by the index (if you know what the index is):
things[1].each {|color| ... }
Or, you can assign it to a variable in a similar way. As long as you know the colors will always be in the second position, you can do this:
_, colors = *things
colors.each {|color| ... }
One of the exercises in this tutorial is:
Exploit the fact that map always returns an array: write a method hash_keys that accepts a hash and maps over it to return all the keys in a linear Array.
The solution is:
def hash_keys(hash)
hash.map { |pair| pair.first }
end
However, I'm having trouble understanding why the above works. For example, I wrote a solution as follows that also works:
def hash_keys(hash)
# Initialize a new array
result = Array.new
# Cycle through each element of the hash and push each key on to our array
hash.map { |x,y| result.push(x) }
# Return the array
result
end
I can understand why my method works, but I don't understand their proposed solution. For example, they are not even creating an Array object. They are not returning anything. It seems they are just listing the first element in each key/value element array.
I think you misunderstood the point of map. It doesn't just iterate over the given collection (that's what each is for) - it creates an array where each element is the result of calling the block with the corresponding element of the original collection.
Your solution could (and should) just as well be written using each instead of map as you aren't really making use of what map does - you're only making use of the fact that it invokes its block once for each element in the given collection.
When map is applied to a hash, the hash is converted to an array. That is why explicit conversion into an array is not necessary. And map returns an array by replacing each item of the original array with the result of evaluating the block. Each time the block is evaluated, it will be given an array that is a pair of a key and its value. first applies to this pair and returns the key. map returns an array of these keys.
map turns an Enumerable object into an Array. It's what it does. The block describes, in terms of each element in the receiver, what the corresponding element in the resulting array should be.
So, a simpler example is map on an Array:
[1,2,3,4].map {|n| n*2}
# => [2,4,6,8]
That is - from [1,2,3,4], generate a new Array, where each element is twice the equivalent entry in [1,2,3,4].
Half of your answer is right in the question: "Exploit the fact that map always returns an array." You don't need to explicitly create an array because map does that for you.
As far as returning it, you already seem to know that the last line of a ruby method is its return value. In the tutorial's solution, since the hash creates an array at the last (and only line), the array is returned from the method.
I can only find methods that look for specific elements of an array.
During my objects.each |a| loop, I want to know when I'm at the final element so I can have a loop like:
objects.each |a|
if objects.hasNext()
puts a.name + ","
else
puts a.name
Iterator's hasNext() determines if the Array's iterator has another element after the one currently being evaluated.
I want to emphasize that I'm looking to print out these values, not turn them in to an Array. .join is not what I'm looking for here.
No, there isn't. However, note that hasNext is not an Array operation in Java, either. It's an Iterator operation, and Ruby's equivalent to Java's Iterator is Enumerator, not Array.
However, Ruby's Enumerator works a little bit different than Java's: instead of asking whether there is a next element, and then advancing the iterator, you simply try to look at the next element and it throws a StopIteration exception when there are no more elements.
So, the equivalent to Java's
iter.hasNext);
would be roughly
begin
enum.peek
true
rescue StopIteration
false
end
However, you almost never iterate manually in Ruby. Instead, you use higher-level iteration methods such as join, flat_map, group_by, uniq, sort, sort_by, inject, map, each_with_object, each etc.
For example:
%w(pretty ugly stupid).join(', ') # => 'pretty, ugly, stupid'
Is there a comparable Array operation to Java's hasNext() in ruby?
First of all Java's Array doesn't have any hasNext method per se because it wouldn't make any sense. It's the iterator that has it. In Ruby there's no such a thing as a list and the powerful iterator methods (each and the each_* family) would make it pretty useless:
my_array.each do |current|
// operations
// implicit:
// if (current.has_next) current = current.next
// else break
end
So, no there's no such a thing.
I'm using .each |a| to run the loop. I want to print a comma each time through unless it's the last. I want this list (pretty, ugly, stupid) not (pretty, ugly, stupid,). Any thoughts
You should take a look at the .join method.
It is common that, when leaning a new language, people tend to looking for something that familiar with:)
Your specific questions could easily be solved by using each_with_index.
objects.each_with_index do |object ,index|
if index == (object.length -1) then
puts a.name + ","
else
puts a.name
end
end
In the Ruby library iterators are implemented as internal iterators in contrast to Java which implements external iterators. The key difference between the two is that the former are designed to not let the client control the iteration, while the latter leave to the client this responsibility.
The purpose of a method like hasNext is to control iteration directly, thus in Ruby no such thing exists. Methods like peek and next defined by Enumerator are, I guess, not intended to control iteration directly but to implement custom internal iterators.
That said, your problem is easily solved with this code:
puts objects.map(&:name).join(', ')
However sometimes could be useful to concoct your own internal iterator using an Enumerator object:
module Enumerable
def puts_each_with_separator(separator)
enum = each
loop do
print yield(enum.next)
enum.peek rescue break
print separator
end
puts
end
end
objects.puts_each_with_separator(', ', &:name)
I want to emphasize that I'm looking to print out these values, not
turn them in to an Array. .join is not what I'm looking for here.
Actually, I think .join is exactly what you're looking for. The result of .join is a string, not an array, so
puts objects.join(",")
does what you say you want.