I want to know how does Array’s each method (block) change its elements ?
It doesn’t. You do.
b = a.each { |x| x + 1}
This executes “x + 1” for every element in the array. Compare the
following:
x = 5
x + 1
p x
x is still 5. The expression x+1 does not change the value of x.
b = a.each { |x| x << “-” }
x = “foo”
x << “-”
p x
Prints “foo-” because << does modify the receiver. I.e. after calling <<
“-”
the string will contain a “-”, so that’s what’s happening to each
element in
the array.
Another note: each returns the receiver, so if you do
b = a.each {…}
b and a will point to the exact same array no matter what happens in the
block
(unless you use break inside the block).
I want to know how does Array’s each method (block) change
its elements ?
each just iterates on each element/object of the array. an array is just
a container of objects (wc includes also arrays). if you use << or
concat method, you change the object, ergo, you change the array too.
try array#map and just use simple + for concatenation, eg
a
=> [“how”, “are”, “you”]
c = a.map{ |x| x + “-” }
=> [“how-”, “are-”, “you-”]
a
=> [“how”, “are”, “you”]
c
=> [“how-”, “are-”, “you-”]
also note, strings are mutable objects, but, numbers are not.
see,
a=[1,2,3]
=> [1, 2, 3]
b=a.each{|x| x+=1}
=> [1, 2, 3]
a
=> [1, 2, 3]
b
=> [1, 2, 3]
no change
the expression x+=1 seems to change the object pointed by var x. but no.
a new object (eg 2) is now pointed by x, wc is outside of the array.
ruby cannot change the object 1. for ruby, 1 is always 1. Since we did
not do anything on the new objects 2,3,4, they just get lost/cleanuped.
They were there before. You can print them if you’re in doubt. But you
can save them easily if you use array#map.
I have noticed that Number elements and String elements of an array
generate diffrent results in its EACH method if you change the
elements.
That’s not true. You simply can not change a Numeric object.
But it is difficult to understand how ruby implements
arrays each method block.
Array’s each method is implemented like this, basically:
class Array
def each()
0.upto(length-1) do |i|
yield self[i]
end
return self
end
end
Except that in reality it’s a) not implemented in ruby and b) not using
upto.
But if you’d redefine each using the above code there should be no
difference
in behaviour except if you also redefine upto.
I have noticed that Number elements and String elements of an array
generate diffrent results in its EACH method if you change the
elements. But it is difficult to understand how ruby implements
arrays each method block.
They are treated the same way.
Try this:
a = [1, 2, 3, 4, 5]
a.each {|x| x + 1}
puts a
b = [“1”, “2”, “3”, “4”, “5”]
b.each {|x| x + “1”}
puts b
Array#each has nothing to say about changing each element. It’s about
difference between “+” and “<<” methods. “+” just create new object
and doesn’t change original objects. “<<” for String object changes
object from left side. There is also “<<” for integers but it works
different and doesn’t change objects because of fact that integers are
immutable in Ruby.
There is also “<<” for integers but it works
different and doesn’t change objects because of fact that integers are
immutable in Ruby.
Well, I would assume that if Integers were mutable, << would still not be a
mutating method as that would really not make much sense.
I think that the key idea here is that the block argument of each (or
any iterator method for that matter) can’t affect an element of the
collection unless it invokes a mutating method on that element.
The fact that immutable objects like integers don’t HAVE any mutating
methods (by definition) is a bit of an aside.
I have noticed that Number elements and String elements of an array
generate diffrent results in its EACH method if you change the
elements. But it is difficult to understand how ruby implements
arrays each method block.