How does Array's each method change its elements?

Hi,

I found Array's each method (block) changes its elements sometimes,
but sometimes it don't.

Please look this:

a = [1,2,3,4,5]
b = a.each { |x| x + 1}

puts a
[1,2,3,4,5]
puts b
[1,2,3,4,5]

The array keeps no changed.

But, look another:

a = ["how","are","you"]
b = a.each { |x| x << "-" }
puts a
["how-","are-","you-"]
puts b
["how-","are-","you-"]

The array changed!

I want to know how does Array's each method (block) change its elements ?

Thank you.

···

--
Wang

w wg wrote:

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).

HTH,
Sebastian

···

--
Jabber: sepp2k@jabber.org
ICQ: 205544826

#..
# a = ["how","are","you"]
# b = a.each { |x| x << "-" }
# puts a
# ["how-","are-","you-"]
# puts b
# ["how-","are-","you-"]

···

From: w wg [mailto:duzuike@gmail.com]
#
# The array changed!
#
# 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.

let's use again map

b=a.map{|x| x+=1}

=> [2, 3, 4]

a

=> [1, 2, 3]

b

=> [2, 3, 4]

hth
kind regards -botp

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.

···

2008/9/26 Peña, Botp <botp@delmonte-phil.com>:

From: w wg [mailto:duzuike@gmail.com]
#..
# a = ["how","are","you"]
# b = a.each { |x| x << "-" }
# puts a
# ["how-","are-","you-"]
# puts b
# ["how-","are-","you-"]
#
# The array changed!
#
# 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.

let's use again map

b=a.map{|x| x+=1}

=> [2, 3, 4]

a

=> [1, 2, 3]

b

=> [2, 3, 4]

hth
kind regards -botp

--
--
WenGe Wang

w wg wrote:

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.

HTH,
Sebastian

···

--
Jabber: sepp2k@jabber.org
ICQ: 205544826

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.

···

On Sat, Sep 27, 2008 at 9:55 AM, w wg <duzuike@gmail.com> wrote:

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.

--
Radosław Bułat

http://radarek.jogger.pl - mój blog

Radosław Bułat wrote:

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.

···

--
Jabber: sepp2k@jabber.org
ICQ: 205544826

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.

···

2008/9/27 Sebastian Hungerecker <sepp2k@googlemail.com>:

Radosław Bułat wrote:

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.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/