Map (collect) not doing what it should

example 1 works, I tried to avoid being repetitive and I got example 2
which doesn’t work. I am using Ruby 1.9.3

#--------------------------------------------
#example 1

def do_something(x)
x.upcase

.upcase is just for this example, I use far more complicated

function in my code

end

my_array = [“aaa”, “bbb”, “ccc”]

a, b, c = my_array

a = do_something(a)
b = do_something(b)
c = do_something©

puts "a = " + a
puts "b = " + b
puts "c = " + c

#output:

a = AAA

b = BBB

c = CCC

#--------------------------------------------
#example 2

def do_something(x)
x.upcase
end

my_array = [“aaa”, “bbb”, “ccc”]

a, b, c = my_array

[a,b,c].map! { |x| x = do_something(x) }

puts "a = " + a
puts "b = " + b
puts "c = " + c

#output:

a = aaa

b = bbb

c = ccc

#--------------------------------------------
#example 3

def do_something(x)
x.upcase
end

x = [“aaa”, “bbb”, “ccc”]

x.map! { |n| do_something(n) }

puts x.inspect
#---------------------------------------------

Example 3 also works as expected … whats wrong with example 2 ?!?

what do you know,
a,b,c = [a,b,c].map! { |x| x = do_something(x) }
actually works

I tried:
[a,b,c] = [a,b,c].map! { |x| x = do_something(x) }
but it returned error

There’s so many little stuff you gotta know, I wasted whole 2 hours on
this “problem” :frowning:

I thought since I used explicit method map! that it will alter value of
each separate variable that’s member of that array, but apparently it
doesn’t

a = 5
[a].map! {|x| x*2 }
#=> [10]

puts a
#=> 5

I thought since I used explicit method map! that it will alter value of
each separate variable that’s member of that array, but apparently it
doesn’t

a = 5
[a].map! {|x| x*2 }
#=> [10]

puts a
#=> 5

It does, what it should:

a = [5]
puts a.map! {|x| x*2 }
#=> 10

puts a
#=> 10

You’re mapping the array containing a,b, and c; but you don’t keep that
array.

On Thu, Dec 5, 2013, at 16:11, Stu P. D’naim wrote:

I thought since I used explicit method map! that it will alter value of
each separate variable that’s member of that array, but apparently it
doesn’t

a = 5
[a].map! {|x| x*2 }
#=> [10]

puts a
#=> 5

Fixnum objects are immutable, ie. they never change.
Try with an array of strings:

a = “+”
[a].map {|x| x << “+” }
=> “++”

a
=> “++”

Note that there is no need to use #map!, as you don’t
store your array anywhere. If you’re not even going to
use the return value of #map you may as well use #each
instead.

The difference between #map and #map! becomes apparent
with this example:

array = [1, 2, 3]

array.map {|x| x + 1 }
=> [2, 3, 4]

array
=> [1, 2, 3] # map hasn’t changed the array

array.map! {|x| x + 1 }
=> [2, 3, 4]

array
=> [2, 3, 4] # map! did change the array

On Thu, Dec 5, 2013 at 4:11 PM, Stu P. D’naim [email protected]
wrote:

I thought since I used explicit method map! that it will alter value of
each separate variable that’s member of that array, but apparently it
doesn’t

a = 5
[a].map! {|x| x*2 }
#=> [10]

puts a
#=> 5

You want String#upcase! and Array#each then, because apparently you
want to change String instances in place:

irb(main):001:0> my_array = [“aaa”, “bbb”, “ccc”]
=> [“aaa”, “bbb”, “ccc”]
irb(main):002:0> my_array.each {|s| s.upcase!}
=> [“AAA”, “BBB”, “CCC”]
irb(main):003:0> my_array
=> [“AAA”, “BBB”, “CCC”]

Even shorter without a block:

irb(main):004:0> my_array = [“aaa”, “bbb”, “ccc”]
=> [“aaa”, “bbb”, “ccc”]
irb(main):005:0> my_array.each(&:upcase!)
=> [“AAA”, “BBB”, “CCC”]
irb(main):006:0> my_array
=> [“AAA”, “BBB”, “CCC”]

Kind regards

robert

I don’t want to upcase, that was just example.
What I am trying to do is to make this shorter:

#--------------------
a = do_something(a)
b = do_something(b)
c = do_something©
.
.
.
z = do_something(z)
#--------------------

So far, the best solution I have is:
#-------------------------------------------------------------
a,b,c … z = [a,b,c … z].map {|x| x = do_something(x)}
#-------------------------------------------------------------

I’m not sure if it could be made even more shorter and simple

On Dec 5, 2013, at 11:59, Stu P. D’naim [email protected] wrote:

a,b,c … z = [a,b,c … z].map {|x| x = do_something(x)}

Having that many variables is a design smell, esp when it seems that
they don’t really mean anything and you have to act across them in a
uniform way.

data = {…}

data.each do |key, val|
data[key] = do_something val
end

haha, I don’t really have 26 variables … I have only three … but I
sort of wanted to know theoretically, if there is a shorter way to do:

a = do_something(a)
b = do_something(b)
c = do_something©

because of DRY principle of programming I’ve been reading everywhere.

Sorry for being inconclusive when formulating my original post. I’d
gladly post original chunks of my code, but they are not in english, so
I thought I would get better response here if I simplify example with
english names for variables, methods etc

Are you able to provide an excerpt from your real code? Perhaps a
larger-scale refactoring is in order.

[“aaa”, “bbb”, “ccc”].each do |something|
/clean your room/
end

=)

fixnum * integer --> numberic_result
#it’s mean in this case: map! equal map
#notify: “!” dosen’t take effect anywhere,somewhere haven’t implements
“!”,if u want to use it, u need to implement it by urself first. or
change another way, such as: fixnum << 1

for detail, see the doc about “fixnum”

On 12/05/2013 07:11 AM, Stu P. D’naim wrote:

There is a fundamental misunderstanding here of how Ruby variables work.

a,b,c = [a,b,c].map! { |x| x = do_something(x) }

^- this is working because you are reassigning to a, b, and c. The “x =
…” does nothing, it’s assigning to the local variable “x” inside the
block. Coincidentally, the result of an assignment is the value
assigned. This value happens to be returned by the block because it is
the last expression in the block. After calling #map!, the array
contains the results of calling do_something on each variable. As noted
elsewhere, though, #map would work just as well in this case because the
array is never explicitly stored anywhere.

The contents of the array are assigned back to a, b, and c in the
assignment expression. Ruby matches the variables to values in the array
by position. In other words, “c, b, a = [a,b,c].map! { … }” would have
a different result.

Each time the block is called, a new local variable “x” is created which
refers to the value of an element from the array. It does not refer to
the variables “a, b, c”. In fact, there is no way to get at those
variables from the array, because the array just contains the values
referred to by those variables. The values don’t know what variables
refer to them.

Consider this:

$ irb
2.0.0p247 :001 > a = 1
=> 1
2.0.0p247 :002 > b = a
=> 1
2.0.0p247 :003 > b
=> 1
2.0.0p247 :004 > a = 2
=> 2
2.0.0p247 :005 > b
=> 1

In Ruby assignments, the right-hand side is always a value. The
left-hand side is a name/label/variable. Variables refer to values, not
other variables. So you cannot hand a variable to a method or block and
change the value it refers to. Occasionally you can modify the value
itself, but that is not the same as changing which value the variable is
referring to.

Hope that clarifies a little bit.

-Justin