How to #rewind the internal position under #each? - ruby

I'm trying to write a code where the enumeration sequence is rewinded to the beginning.
I think rewind is appropriate for this application, but I'm not sure how to implement it under an each iterator passing to a block? In the Ruby-Docs example, next is used to move the internal position by one at a time. With a block, it would move autonomously.
There's not many good examples online for this specifically. My workaround at the moment is to nest an iterator under a loop and using break under the iterator. When the iterator breaks, the loop resets the enumeration sequence.
Is there a better way—as I'm sure there is—of doing this?

Use the Enumerator#rewind method from Ruby core class libarary.
Rewinds the enumeration sequence to the beginning.If the enclosed object responds to a “rewind” method, it is called.
a = [1,2,3,4]
enum= a.each
enum # => #<Enumerator: [1, 2, 3, 4]:each>
enum.next # => 1
enum.next # => 2
enum.rewind # => #<Enumerator: [1, 2, 3, 4]:each>
enum.next # => 1

Related

Reassign entire array to the same reference

I've searched extensively but sadly couldn't find a solution to this surely often-asked question.
In Perl I can reassign an entire array within a function and have my changes reflected outside the function:
#!/usr/bin/perl -w
use v5.20;
use Data::Dumper;
sub foo {
my ($ref) = #_;
#$ref = (3, 4, 5);
}
my $ref = [1, 2];
foo($ref);
say Dumper $ref; # prints [3, 4, 5]
Now I'm trying to learn Ruby and have written a function where I'd like to change an array items in-place by filtering out elements matching a condition and returning the removed items:
def filterItems(items)
removed, items = items.partition { ... }
After running the function, items returns to its state before calling the function. How should I approach this please?
I'd like to change an array items in-place by filtering out elements matching a condition and returning the removed items [...] How should I approach this please?
You could replace the array content within your method:
def filter_items(items)
removed, kept = items.partition { |i| i.odd? }
items.replace(kept)
removed
end
ary = [1, 2, 3, 4, 5]
filter_items(ary)
#=> [1, 3, 5]
ary
#=> [2, 4]
I would search for pass by value/reference in ruby. Here is one I found first https://mixandgo.com/learn/is-ruby-pass-by-reference-or-pass-by-value.
You pass reference value of items to the function, not the reference to items. Variable items is defined out of method scope and always refers to same value, unless you reassign it in the variable scope.
Also filterItems is not ruby style, see https://rubystyle.guide/
TL;DR
To access or modify an outer variable within a block, declare the variable outside the block. To access a variable outside of a method, store it in an instance or class variable. There's a lot more to it than that, but this covers the use case in your original post.
Explanation and Examples
In Ruby, you have scope gates and closures. In particular, methods and blocks represent scope gates, but there are certainly ways (both routine and meta) for accessing variables outside of your local scope.
In a class, this is usually handled by instance variables. So, as a simple example of String#parition (because it's easier to explain than Enumerable#partition on an Array):
def filter items, separator
head, sep, tail = items.partition separator
#items = tail
end
filter "foobarbaz", "bar"
#=> "baz"
#items
#=> "baz"
Inside a class or within irb, this will modify whatever's passed and then assign it to the instance variable outside the method.
Partitioning Arrays Instead of Strings
If you really don't want to pass things as arguments, or if #items should be an Array, then you can certainly do that too. However, Arrays behave differently, so I'm not sure what you really expect Array#partition (which is inherited from Enumerable) to yield. This works, using Enumerable#slice_after:
class Filter
def initialize
#items = []
end
def filter_array items, separator
#items = [3,4,5].slice_after { |i| i == separator }.to_a.pop
end
end
f = Filter.new
f.filter_array [3, 4, 5], 4
#=> [5]
Look into the Array class for any method which mutates the object, for example all the method with a bang or methods that insert elements.
Here is an Array#push:
ary = [1,2,3,4,5]
def foo(ary)
ary.push *[6, 7]
end
foo(ary)
ary
#=> [1, 2, 3, 4, 5, 6, 7]
Here is an Array#insert:
ary = [1,2,3,4,5]
def baz(ary)
ary.insert(2, 10, 20)
end
baz(ary)
ary
#=> [1, 2, 10, 20, 3, 4, 5]
Here is an example with a bang Array#reject!:
ary = [1,2,3,4,5]
def zoo(ary)
ary.reject!(&:even?)
end
zoo(ary)
ary
#=> [1, 3, 5]
Another with a bang Array#map!:
ary = [1,2,3,4,5]
def bar(ary)
ary.map! { |e| e**2 }
end
bar(ary)
ary
#=> [1, 4, 9, 16, 25]

We have 'index' and 'rindex', we have 'find' but no 'rfind'

When applied to an Array, index (invoked with a block) returns the index of the first element satisfying the condition, and rindex returns the index of the last one. Similarly, we have find to return the element itself. However, there is no corresponding rfind that would return the last element of an array satisfying a condition.
Does Ruby already have a method that accomplishes this?
Before monkey-patching the Array class, I want to make sure.
You can do it like this:
enum = [1, 2, 3, 4].reverse_each
# => #<Enumerator: [1, 2, 3, 4]:reverse_each>
enum.find(&:odd?)
# => 3
Notice that, unlike using Array#reverse, it does not create a temporal array that is thrown out immediately.
Doing it at once:
[1, 2, 3, 4].reverse_each.find(&:odd?)
# => 3
In other words, we have reverse_each.find instead of rfind; not a big deal.

Ruby enumerable reset?

I'm having trouble understanding exactly how much state a ruby enumerable keeps.
I know some python, so I was expecting that after I take an item from an enumerable, it's gone and the next item will be returned as I take another item.
Strangely, this does happen when I use next but not when I use anything like take of first.
Here's an example:
a = [1,2,3].to_enum
# => #<Enumerator: [1, 2, 3]:each>
a.take(2)
# => [1, 2]
a.next
# => 1
a.next
# => 2
a.take(2)
# => [1, 2]
a.next
# => 3
a.next
# StopIteration: iteration reached an end
# from (irb):58:in `next'
# from (irb):58
# from /usr/bin/irb:12:in `<main>'
a.take(2)
# => [1, 2]
It seems like the enumerable keeps state between next calls, but resets before each take call?
It may be a little confusing, but it's important to note that in Ruby there is the Enumerator class and the Enumerable module.
The Enumerator class includes Enumerable (like most of enumerable objects such as Array, Hash, etc.
The next method is provided as part of the Enumerator, which indeed has an internal state. You can consider an Enumerator very close to the concept of Iterator exposed by other languages.
When you instantiate the Enumerator, the internal pointer points to the first item in the collection.
2.1.5 :021 > a = [1,2,3].to_enum
=> #<Enumerator: [1, 2, 3]:each>
2.1.5 :022 > a.next
=> 1
2.1.5 :023 > a.next
=> 2
This is not the only purpose of the Enumerator (otherwise it would probably be called Iterator). However, this is one of the documented feature.
An Enumerator can also be used as an external iterator. For example, #next returns the next value of the iterator or raises StopIteration if the Enumerator is at the end.
e = [1,2,3].each # returns an enumerator object.
puts e.next # => 1
puts e.next # => 2
puts e.next # => 3
puts e.next # raises StopIteration
But as I said before, the Enumerator class includes Enumerable. It means every instance of an Enumerator exposes the Enumerable methods that are designed to work on a collection. In this case, the collection is the one the Enumerator is wrapped on.
take is a generic Enumerable method. It is designed to return the first N elements from enum. It's important to note that enum is referring to any generic class that includes Enumerable, not to the Enumerator. Therefore, take(2) will returns the first two elements of the collection, regardless the position of the pointer inside the Enumerator instance.
Let me show you a practical example. I can create a custom class, and implement Enumerable.
class Example
include Enumerable
def initialize(array)
#array = array
end
def each(*args, &block)
#array.each(*args, &block)
end
end
I can mix Enumerable, and as long as I provide an implementation for each I get all the other methods for free, including take.
e = Example.new([1, 2, 3])
=> #<Example:0x007fa9529be760 #array=[1, 2, 3]>
e.take(2)
=> [1, 2]
As expected, take returns the first 2 elements. take ignores anything else of my implementation, exactly as in Enumerable, including states or pointers.
Per the documentation, Enumerable#take returns first n elements from the Enumerator, not the next n elements from the cursor. Only the methods from Enumerator are going to operate on that internal cursor; the Enumerable mix-in is just a collection of methods for enumerating which don't necessarily share cursors.
If you wanted, you could implement Enumerator#take to do what you expect:
class Enumerator
def take(n = 1)
n.times.map { self.next }
end
end

getting differences between values in an array

I want to write an Array method in ruby that takes the successive values in the array and returns their differences as a new array (unshifting a '0' in at the beginning).
So feeding the array [4,7,11,16] into the method returns a new array [4,3,4,5].
1) does such a method already exist?
If not, then I think I know how to write it. However,
2) does a method already exist which allows me to test the input array and make sure it only consists of integers and/or floats?
Again, if not, I think I know how to write one.
p [4,7,11,16].unshift(0).each_cons(2).map{|a,b| b-a} # => [4, 3, 4, 5]
Keep it simple:
arr = [4,7,11,16]
last = 0
arr.map { |e| new=e-last; last=e; new }
#=> [4, 3, 4, 5]
Another way:
a = [arr.first]
enum = arr.each
loop do
a << -enum.next + enum.peek
end
a
#=> [4, 3, 4, 5]
Enumerator#peek raises a StopIteration exception when enum is at its last element. Kernel#loop handles the exception by breaking from the loop.
Regarding the first method, I am not aware of any such method in the Ruby Array class.
Regarding the second one, you can do it as explained in this answer:
your_array.all? {|i| i.is_a? Numeric }

Differences between these 2 Ruby enumerators: [1,2,3].map vs. [1,2,3].group_by

In Ruby, is there a functional difference between these two Enumerators?
irb> enum_map = [1,2,3].map
=> #<Enumerator: [1, 2, 3]:map> # ends with "map>"
irb> enum_group_by = [1,2,3].group_by
=> #<Enumerator: [1, 2, 3]:group_by> # ends with "group_by>"
irb> enum_map.methods == enum_group_by.methods
=> true # they have the same methods
What can #<Enumerator: [1, 2, 3]:map> do that <Enumerator: [1, 2, 3]:group_by> can't do, and vice versa?
Thanks!
From the documentation of group_by:
Groups the collection by result of the block. Returns a hash where the
keys are the evaluated result from the block and the values are arrays
of elements in the collection that correspond to the key.
If no block is given an enumerator is returned.
(1..6).group_by { |i| i%3 } #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
From the documentation of map:
Returns a new array with the results of running block once for every
element in enum.
If no block is given, an enumerator is returned instead.
(1..4).map { |i| i*i } #=> [1, 4, 9, 16]
(1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"]
As you can see, each does something different, which serves a different purpose. Concluding that two APIs are the same because they expose the same interface seems to miss the entire purpose of Object Oriented Programming - different services are supposed to expose the same interface to enable polymorphism.
There's a difference in what they do, but fundamentally they are both of the same class: Enumerator.
When they're used the values emitted by the enumerator will be different, yet the interface to them is identical.
Two objects of the same class generally have the same methods. It is possible to augment an instance with additional methods, but this is not normally done.

Resources