Convert enumerator to lazy enumerator - ruby

An enumerator can be converted into a lazy enumerator using Enumerator::Lazy.new like this (this is an example; at the beginning, I already have an enumerator, not an array):
xs_enum = [1, 2, 3].to_enum
# => #<Enumerator: [1, 2, 3]:each>
xs_lazy_enum = Enumerator::Lazy.new(xs_enum, &:yield)
# => #<Enumerator::Lazy: #<Enumerator: [1, 2, 3]:each>:each>
xs_lazy_enum.force
# => [1, 2, 3]
Is there a more succinct way to do it?

You can directly call lazy on the array (or enumerator).
[1, 2, 3].lazy
# => #<Enumerator::Lazy: [1, 2, 3]>

What about:
[1, 2, 3].to_enum.lazy
# => #<Enumerator::Lazy: ...>
Indeed, but the problem is that I start from an enumerator, not from an array
That doesn't change anything:
enum = (1..10).each
# => #<Enumerator: ...>
enum.lazy
# => #<Enumerator::Lazy: ...>
Enumerable#to_enum returns an enumerator. If you chain a call to Enumerable#lazy the receiver of the second message is the Enumerator returned by the first call.

Related

Why a new call of a method with exclamation mark affects all previous calls of that method?

I'm sorry if this is a duplicate - I couldn't find anything similar in the existing posts.
I understand the difference between methods like shuffle and shuffle!. However, I am confused why calling the method more than once would result in changing the variables of all objects that previously referred to it? I'd expect once we apply a method, that the variable gets a value and we're done with it. Not that it continues to refer to the method call and the argument passed and that it would get re-evaluated later on.
I thought it's best to demonstrate with an example:
irb(main):001:1* def shuffle(arr)
irb(main):002:1* arr.shuffle!
irb(main):003:0> end
=> :shuffle
irb(main):004:0> arr = [1,2,3,4]
=> [1, 2, 3, 4]
irb(main):005:0> one = shuffle(arr)
=> [4, 2, 3, 1]
irb(main):006:0> two = shuffle(arr)
=> [1, 2, 4, 3]
irb(main):007:0> one
=> [1, 2, 4, 3]
So, here I'd expect one to stay [4, 2, 3, 1]. However, with each new call, all previous ones would get equated to the latest result of the method call. I realise it should have something to do with calling it with the same argument arr, but still doesn't quite make sense.
Array#shuffle! shuffles the array in-place and returns its receiver:
ary = [1, 2, 3, 4]
ary.equal?(ary.shuffle!) #=> true
Assigning the result from shuffle! to another variable doesn't change this. It merely results in two variables referring to the same array:
a = [1, 2, 3, 4]
b = a.shuffle!
a #=> [2, 4, 1, 3]
b #=> [2, 4, 1, 3]
a.equal?(b) #=> true
You probably want a new array. That's what Array#shuffle (without !) is for:
a = [1, 2, 3, 4]
b = a.shuffle
a #=> [1, 2, 3, 4]
b #=> [2, 4, 1, 3]
Even if shuffle returns the element in the original order, you'll get another array instance:
a = [1, 2, 3, 4]
b = a.shuffle until b == a
a #=> [1, 2, 3, 4]
b #=> [1, 2, 3, 4]
a.equal?(b) #=> false

How to use a recursive array

I have array, named a and define it with [1, 2, 3].
Next, I pushed it to itself:
a = [1, 2, 3]
a << a
and the result I get is:
#=> [1, 2, 3, [...]]
When I want to get the last element of array using a.last I get:
a.last
#=> [1, 2, 3, [...]]
#even
a.last.last.last
#=> [1, 2, 3, [...]]
What is going on, when we would push array to itself?
Yes, I understand that this should create a recursive array, but what can we do with it?
In Ruby variables, array elements etc. are object references. So when you do a = [1, 2, 3], there will be an array somewhere in memory and the a variable is a reference to that memory. Now when you do a << a, a[4] will also be a reference to that object. So in effect a now contains a reference to itself.
a = [1, 2, 3]
a << a.dup
a.last
=> [1, 2, 3]
a.last.last
=> 3
Maybe this is what you wanted. This just insert an array [1, 2, 3] as the last item of the a array. In the way you did you put a reference at the end of the a array and this becomes recursive.

Ruby enumerator with chaining

I am a newbie of Ruby and I don't quite understand the following code.
n = [1,2,3]
n.map!.select{|x| x+=1}
puts n.inspect
will give me
[nil, nil, nil]
I know that n.map! will give me an enumerator but I don't get it why calling select on it will make n becomes nil. I know that map! will modify the original object, I just don't understand how that's achieved.
Update:
I tried n.map!.select {|x| true}, n is still [nil, nil, nil]
I appreciate your help! Thanks!
It's because the select method is used for selection. It returns the element that satisfies the condition you placed in your block. In your case, you didn't put any condition so it returned nil
e.g.
You want to do something like this:
n = [1,2,3]
n.select { |num| num < 3 }
#=> This should return
#=> [1,2]
In the comments, it says:
It's to do with the in-place modification of map!
that's true. Let me make it clearer here:
In the definition of Array#map!, it says:
map! {|item| block } → ary click to toggle source
map! → Enumerator
Invokes the given block once for each element of self, replacing the element with the value returned by the block
So:
Example 1
[58] pry(main)> a = [1,2,3]
=> [1, 2, 3]
[60] pry(main)> e = a.map!
=> #<Enumerator: ...>
[61] pry(main)> e.each {|n| n + 1}
=> [2, 3, 4]
[62] pry(main)> a
=> [2, 3, 4]
However:
Example 2
[71] pry(main)> a = [1,2,3]
=> [1, 2, 3]
[72] pry(main)> e = a.map!
=> #<Enumerator: ...>
[73] pry(main)> e.next
=> 1
[74] pry(main)> a
=> [1, 2, 3]
[75] pry(main)> e.peek
=> 2
[76] pry(main)> a
=> [nil, 2, 3]
I think this due to Enumerator#each call takes a block, and that would be the return value from example 1; but when Enumerator#next is called (same goes to Enumerator.to_a), it cannot evaluate the block, therefore, returning nil.

Ruby enumerator chaining

In this example,
[1, 2, 3].each_with_index.map{|i, j| i * j}
# => [0, 2, 6]
my understanding is that, since each_with_index enumerator is chained to map, map behaves like each_with_index by passing an index inside the block, and returns a new array.
For this,
[1, 2, 3].map.each_with_index{|i, j| i * j}
# => [0, 2, 6]
I'm not sure how to I interpret it.
In this example,
[1, 2, 3, 4].map.find {|i| i == 2}
# => 2
I was expecting the the output to be [2], assuming that map is chained to find, and map would return a new array.
Also, I see this:
[1, 2, 3, 4].find.each_with_object([]){|i, j| j.push(i)}
# => [1]
[1, 2, 3, 4].each_with_object([]).find{|i, j| i == 3}
# => [3, []]
Can you let me know how to interpret and understand enumerator chains in Ruby?
You might find it useful to break these expressions down and use IRB or PRY to see what Ruby is doing. Let's start with:
[1,2,3].each_with_index.map { |i,j| i*j }
Let
enum1 = [1,2,3].each_with_index
#=> #<Enumerator: [1, 2, 3]:each_with_index>
We can use Enumerable#to_a (or Enumerable#entries) to convert enum1 to an array to see what it will be passing to the next enumerator (or to a block if it had one):
enum1.to_a
#=> [[1, 0], [2, 1], [3, 2]]
No surprise there. But enum1 does not have a block. Instead we are sending it the method Enumerable#map:
enum2 = enum1.map
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:each_with_index>:map>
You might think of this as a sort of "compound" enumerator. This enumerator does have a block, so converting it to an array will confirm that it will pass the same elements into the block as enum1 would have:
enum2.to_a
#=> [[1, 0], [2, 1], [3, 2]]
We see that the array [1,0] is the first element enum2 passes into the block. "Disambiguation" is applied to this array to assign the block variables the values:
i => 1
j => 0
That is, Ruby is setting:
i,j = [1,0]
We now can invoke enum2 by sending it the method each with the block:
enum2.each { |i,j| i*j }
#=> [0, 2, 6]
Next consider:
[1,2,3].map.each_with_index { |i,j| i*j }
We have:
enum3 = [1,2,3].map
#=> #<Enumerator: [1, 2, 3]:map>
enum3.to_a
#=> [1, 2, 3]
enum4 = enum3.each_with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:map>:each_with_index>
enum4.to_a
#=> [[1, 0], [2, 1], [3, 2]]
enum4.each { |i,j| i*j }
#=> [0, 2, 6]
Since enum2 and enum4 pass the same elements into the block, we see this is just two ways of doing the same thing.
Here's a third equivalent chain:
[1,2,3].map.with_index { |i,j| i*j }
We have:
enum3 = [1,2,3].map
#=> #<Enumerator: [1, 2, 3]:map>
enum3.to_a
#=> [1, 2, 3]
enum5 = enum3.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:map>:with_index>
enum5.to_a
#=> [[1, 0], [2, 1], [3, 2]]
enum5.each { |i,j| i*j }
#=> [0, 2, 6]
To take this one step further, suppose we had:
[1,2,3].select.with_index.with_object({}) { |(i,j),h| ... }
We have:
enum6 = [1,2,3].select
#=> #<Enumerator: [1, 2, 3]:select>
enum6.to_a
#=> [1, 2, 3]
enum7 = enum6.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:select>:with_index>
enum7.to_a
#=> [[1, 0], [2, 1], [3, 2]]
enum8 = enum7.with_object({})
#=> #<Enumerator: #<Enumerator: #<Enumerator: [1, 2, 3]:
# select>:with_index>:with_object({})>
enum8.to_a
#=> [[[1, 0], {}], [[2, 1], {}], [[3, 2], {}]]
The first element enum8 passes into the block is the array:
(i,j),h = [[1, 0], {}]
Disambiguation is then applied to assign values to the block variables:
i => 1
j => 0
h => {}
Note that enum8 shows an empty hash being passed in each of the three elements of enum8.to_a, but of course that's only because Ruby doesn't know what the hash will look like after the first element is passed in.
Methods you are mentioning are defined on Enumerable objects. These methods behave differently depending on whether you pass a block or not.
When you do not pass a block, they typically return an Enumerator object, to which you can chain further methods like each_with_index, with_index, map, etc.
When you pass a block to these methods, they return different kinds of object depending on what will make sense for that particular method.
For methods like find, its purpose is to find the first object that satisfies a condition, and it does not make particular sense to wrap that in an array, so it returns that object bare.
For methods like select or reject, their purpose is to return all relevant objects, so they cannot return a single object, and they have to be wrapped in an array (even when the relevant object happens to be a single object).

Is there a particular function to retrieve then delete random array element?

I know I can do this in a couple of steps, but was wondering if there is a function which can achieve this.
I want to array#sample, then remove the element which was retrieved.
How about this:
array.delete_at(rand(array.length))
Another inefficient one, but super obvious what's going on:
array.shuffle.pop
What would be nice would be a destructive version of the sample method on Array itself, something like:
class Array
def sample!
delete_at rand length
end
end
Linuxios's has it perfect. Here is another example:
array = %w[A B C]
item_deleted = array.delete_at(1)
Here it is in irb:
1.9.2p0 :043 > array = %w[A B C]
=> ["A", "B", "C"]
1.9.2p0 :044 > item_deleted = array.delete_at(1)
=> "B"
1.9.2p0 :045 > array
=> ["A", "C"]
1.9.2p0 :047 > item_deleted
=> "B"
An alternative to the rand(array.length) approach already mentioned, could be this one
element = array.delete array.sample
Eksample:
>> array = (1..10).to_a
>> element = array.delete array.sample
>> array # => [1, 2, 4, 5, 6, 7, 8, 9, 10]
>> element # => 3
This is also a set of two operations, but at least you won't have to move away from the array itself.
If you need to sample a number of items and the remove those from the original array:
array = (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
grab = array.sample(4)
=> [2, 6, 10, 5]
grab.each{ |a| array.delete a }
=> [2, 6, 10, 5]
array
=> [1, 3, 4, 7, 8, 9]

Resources