Ruby enumerator with chaining - ruby

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.

Related

Reduce hash with key, value and index as block parameters

h = { "a" => 1, "b" => 2 }
Is there a way to reduce a hash and have the key, value and index as block parameters?
As a starting point I can iterate over a hash getting key, value and index:
h.each_with_index { |(k,v), i| puts [k,v,i].inspect }
# => ["a", 1, 0]
# => ["b", 2, 1]
However when I add reduce I seem to loose the ability to have the key and value as separate values and instead they are provided as a two element array:
h.each_with_index.reduce([]) { |memo, (kv,i)| puts [kv,i].inspect }
# => [["a", 1], 0]
# => [["b", 2], 1]
This is okay, I can in the block do kv[0] and kv[1], but I'd like something like this:
h.each_with_index.reduce([]) { |memo, (k,v), i| puts [k,v,i].inspect }
I'd like to do this without monkey-patching.
Maybe something like this?:
h.each_with_index.reduce([]) { |memo, ((k,v), i)| puts [k,v,i].inspect }
#=> ["a", 1, 0]
#=> ["b", 2, 1]
#=> nil
All you need is scoping: ((k,v), i).
Keeping in mind with reduce, we always have to return the object at the end of block. Which is kind of an extra overhead unless last operation isn't on the memo object which returns the object itself.Otherwise it won't return the desired result.
Same thing can be achieved with each_with_index chained with with_object like so:
h.each_with_index.with_object([]) { |((k,v), i), memo| memo << [k,v,i].inspect }
#=> ["a", 1, 0]
#=> ["b", 2, 1]
#=> []
See the array at last line of output? That's our memo object, which isn't same as reduce that we used above.
When in doubt what the block arguments are, create an instance of an Enumerator and call #next on it:
▶ h = {a: 1, b: 2}
#⇒ {:a=>1, :b=>2}
▶ enum = h.each.with_index.with_object([])
#⇒ #<Enumerator: ...>
▶ enum.next
#⇒ [[[:a, 1], 0], []]
The returned value consists of:
array of key and value, joined into:
array with an index, joined into:
array with an accumulator (for reduce it’d go in front, if reduce returned an enumerator when called without a block—credits to #Stefan for nitpicking.)
Hence, the proper parentheses for decomposing it would be:
# ⇓ ⇓ ⇓ ⇓
# [ [ [:a, 1], 0 ], [] ]
{ | ( (k, v), idx ), memo| ...
Enumerable#each_with_index yields two values into the block: the item and its index. When it is invoked for a Hash, the item is an array that contains two elements: the key and the associated value.
When you declare the block arguments |(k,v), i| you, in fact, deconstruct the first block argument (the item) into its two components: the key and the value. Without a block h.each_with_index produces an Enumerator that yields both arguments of the previously used block wrapped into an array.
This array is the second argument of Enumerator#reduce.
You can tell this by running:
irb> h.each_with_index.reduce([]) { |memo, j| p j }
[["a", 1], 0]
[["b", 2], 1]
Now, the answer to your question is easy: just deconstruct j and you get:
irb> h.each_with_index.reduce([]) { |memo, ((k,v), i)| puts [k,v,i].inspect }
["a", 1, 0]
["b", 2, 1]
Of course, you should memo << [k,v,i] or put the values in memo using other other rules and return memo to get your final desired result.

Convert enumerator to lazy enumerator

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.

What is the difference of Ruby's Array#to_a method

For example:
a = [1,2,3,4]
b = a
c = a.to_a
a.insert(0,0) #=> [0,1,2,3,4]
b #=> [0,1,2,3,4]
c #=> [0,1,2,3,4]
Why the output of array b and c is the same? If I want to get a copy of array a, not a reference one, which method should I use?
Why the output of array b and c is the same?
Because all three local variables referencing the same objects,as below:
a = [1,2,3,4]
b = a
c = a.to_a
a.object_id
# => 72187200
b.object_id
# => 72187200
c.object_id
# => 72187200
If i want to get a copy of array a, not a reference one , which method should i use?
Then use a.dup.Here documented Object#dup
a = [1,2,3,4]
b = a.dup
c = a.dup
a.object_id
# => 82139270
b.object_id
# => 82139210
c.object_id
# => 82134600
a.insert(0,0) # => [0, 1, 2, 3, 4]
b # => [1, 2, 3, 4]
c # => [1, 2, 3, 4]
Array#to_a says : Returns self.If called on a subclass of Array, converts the receiver to an Array object.
So it will not be helpful as per your need.
This is because Array#to_a returns self, so both variables contain a reference to the same Array object. In order to get a new Array with the same contents, you can use either dup or clone (read about the differences between dup and clone):
a = [1, 2, 3]
b = a.dup
a << 4
a #=> [1, 2, 3, 4]
b #=> [1, 2, 3]
Note, however, that the same object references are stored in the new array. This means if you mutate the objects themselves they will still change in both arrays:
a = ['foo', 'bar']
b = a.dup
a[0] << 'baz'
a #=> ["foobaz", "bar"]
b #=> ["foobaz", "bar"]
This is because dup and clone are shallow-copies.
Array#to_a returns the receiver. That is why b and c refer to the same thing. Regarding why to_a returns the original array, in principle, it could be defined one or the other way, but I guess one use case for to_a is to apply it to a variable that is potentially nil to ensure it becomes an array.
some_value.to_a # => `[]` if `some_value` is `nil`
In such use case, you don't need to replace the array with another one in case the receiver is already an array. That would be performantly more preferable.
The reason for that is that variables are merely references to data. Variables are stored in memory; variables keep address of where they are located in a memory. So when you do:
a = b
Those two variables point to the same memory location, hence if you alter a, b is altered as well because it is the same object.
There are a few ways to force Ruby to create another copy of the object. The most popular one is the dup method mentioned by LBg. Note however that it is only creating a shallow copy. If you run:
a = ['foo','bar', []]
b = a.dup
a << 'blah'
b #=> ['foo', 'bar', []] as expected but
b[3] << blah
a #=> ['foobar', 'bar', ['blah]]
The reason for that is that array is in fact an array of references and nested array has not been duplicated when performing dup, so they are the same object.
To create a deep copy of an object, you can use the Marshall module:
b = Marshal.load(Marshal.dump(a))
However, usually you don't really need to do this. Also, some objects cannot be duplicated (e.g. symbols).
You can just do
b = a.dup
OLD POST
You can try this if there is no easier way
b = a.map {|x| x}
It works
1.9.3-p448 :001 > a = [1,2,3] => [1, 2, 3]
1.9.3-p448 :002 > b = a => [1, 2, 3]
1.9.3-p448 :003 > c = a.map{|x| x} => [1, 2, 3]
1.9.3-p448 :004 > a<<0 => [1, 2, 3, 0]
1.9.3-p448 :005 > b => [1, 2, 3, 0]
1.9.3-p448 :006 > c => [1, 2, 3]
But it is a shallow copy though.
According to this post, a.dup is the easier way.

Making map! enumerator do what I want

Having an array
a = 1, 2, 3, 4
And an enumerator:
e = a.map!
Then, by calling e.next repeatedly, array a gets nicely destroyed:
e.next #=> 1
a #=> [1, 2, 3, 4]
e.next #=> 2
a #=> [nil, 2, 3, 4]
e.next #=> 3
a #=> [nil, nil, 3, 4]
That's so hilarious! But when I try
e.next { |x| 2 * x } # => 4
I get
a #=> [nil, nil, nil, 4]
instead of desired
a #=> [nil, nil, nil, 8]
What am I misunderstanding? How to make a.map! do what I want with the elements?
My problem is, that I do not fully understand enumerators. With the previous code in place, for example, enumerator e constitutes a backdoor to a:
e.each { 42 }
a #=> [42, 42, 42, 42]
I would like to know, how to do this gradually, with values other than nil. (I can gradually fill it with nils using e.rewind and e.next several times, as I shown before.
To make map! behave as you want, you need the Enumerator#feed method, consider this
ary = *1..4
enum = ary.map!
# the `loop` method handles `StopIteration` for us
loop do
x = enum.next
enum.feed(x * 2)
end
ary
# => [2, 4, 6, 8]
From reference it seems that Enumerator#next doesn't accept a block, so that doesn't have effect of your next call. If you just want to in-place double the last element while clearing all other, do something like, consider straight approach (like a = a[0..-2].map!{|x| nil} + [a.last*2], maybe more elegant). Anyway, could you please provide us with a more detailed usecase to make sure you are doing what you really need?
a.map! accepts a block, but returns an enumerator if no block is supplied. Enumerator#next does not accept a block.
You want to use this to accomplish your goal:
a.map! {|x| x * 2}
if you want to multiply all elements in the array by 2.
For info on next, check out http://ruby-doc.org/core-2.0/Enumerator.html#method-i-next
If you want the output to be exactly [nil, nil, nil, 8] you could do something like:
func = lambda { |x|
unless x == 4
nil
else
x * 2
end
}
a.map!(&func) #> [nil, nil, nil, 8]

Creating and iterating a 2d array in Ruby

I have very little knowledge about Ruby and cant find a way to create 2d array. Can anyone provide me some snippets or information to get me started?
a = [[1, 2], [3, 4]]
a.each do |sub|
sub.each do |int|
puts int
end
end
# Output:
# 1
# 2
# 3
# 4
or:
a = [[1, 2], [3, 4]]
a.each do |(x, y)|
puts x + y
end
# Output:
# 3
# 7
The easiest way to create a 2d array is by the following:
arr1 = Array.new(3) { Array.new(3)}
The code above creates a 2D array with three rows and three columns.
Cheers.
irb(main):001:0> a = []
=> []
irb(main):002:0> a1 = [1, 2]
=> [1, 2]
irb(main):003:0> a2 = [3, 4]
=> [3, 4]
irb(main):004:0> a.push a1
=> [[1, 2]]
irb(main):005:0> a.push a2
=> [[1, 2], [3, 4]]
irb(main):006:0> a
=> [[1, 2], [3, 4]]
irb(main):007:0> a[0]
=> [1, 2]
irb(main):008:0> a[0][1]
=> 2
Ruby doesn't have the concept of 2-dimensional arrays like C does. Arrays in Ruby are dynamic -- meaning you can resize them a will. They can contain any object or value in each "slot" - including another Array!
In the examples given by #JunaidKirkire and #simonmenke, you have an array which has arrays for its values. You can access the values using the syntax similar to C - but you could also have the case where one slot is an Array and another is just a number, or a String, or a Hash...
You may want to work through a Ruby tutorial to get a better idea of how it works. I like RubyMonk but there are other good ones out there as well.
Creating a 2d array in Ruby
In ruby, every method accepts a block.
two_d_array = Array.new(3) do
Array.new(3) do
0
end
end
The same can be written In oneline (macro style)
two_d_array = Array.new(3) { Array.new(3) { 0 } }
Output
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
Iterating a 2d array in Ruby
I can think of three ways.
1: Using range
(0...two_d_array.size).each do |i|
(0...(two_d_array[i].length)).each do |j|
puts two_d_array[i][j]
end
end
2: Using for
for i in (0...two_d_array.size)
for j in (0...two_d_array[i].length)
puts two_d_array[i][j]
end
end
3: Using Each_with_index method
two_d_array.each_with_index do |sub_array, i|
sub_array.each_with_index do |item, j|
puts two_d_array[i][j]
end
end

Resources