Modify the array in place - Ruby

I'm wondering why the following won't modify the array in place.

I have it:

@card.map!.with_index {|value, key|  key.even? ? value*=2 : value}

      

which just iterates over the array and doubles the values ​​for all even keys.

Then I do:

@card.join.split('').map!{|x| x.to_i}

      

Which concatenates the array into one huge number, splits them into individual numbers, and then maps them back to integers in the array. The only real change from the first step is step 1 will look like a = [1,2,12] and the second step will look like a = [1,2,1,2]. For the second step though I am using .map! when i p @card it appears exactly the same after the first step. I need to set the second step = to something if I want to move on with a new array. Why is this? Has .map! in the second step, don't modify the array in place? Or is method binding denying my ability to do this? Greetings.

+3


source to share


2 answers


TL; DR: A method chain only modifies objects in place if every single method in that chain is an in-place change method.

The important difference in this case is the first method you call on your object. The first example calls map!

that these are methods that modify the array in place. with_index

not important in this example, it just changes the behavior map!

.

The second example calls join

on your array. join

does not modify the array in place, but returns a completely different object: a string. You then take a split

string that creates a new array, and the next one map!

modifies the new array in place.



So in the second example, you need to re-assign the result to your variable:

@card = @card.join.split('').map{ |x| x.to_i }

      

There may be other ways to calculate the desired result. But since you haven't provided any input and output examples, it is not clear what you are trying to achieve.

+2


source


Is there a .map! in the second step, don't modify the array in place?

Yes it does, however the modified array is not @card. The method split()

returns a new array, i.e. The one that is not the @card symbol and displays the card! modifies the new array in place.

Check it:

tap{|x|...} β†’ x
Yields [the receiver] to the block, and then returns [the receiver]. 
The primary purpose of this method is to "tap into" a method chain, 
in order to perform operations on intermediate results within the chain.  

      




@card = ['a', 'b', 'c']
puts @card.object_id

@card.join.split('').tap{|arr| puts arr.object_id}.map{ |x| x.to_i }  #arr is whatever split() returns

--output:--
2156361580
2156361380

      

Every object in a ruby ​​program has a unique object_id.

+2


source







All Articles