Pavel Romanishkin
Pavel Romanishkin

Reputation: 25

What the difference between Ruby + and concat for arrays?

I've been trying to collect arrays with digits into one array. If I try to use + it returns emty array as output. Using concat returns expected array of digits. How does it work and what the main difference between these Ruby methods?

0.step.with_object([]) do |index, output|
  output + [index]
  break output if index == 100
do # returns empty array

0.step.with_object([]) do |index, output|
  output.concat [index]
  break output if index == 100
end # returns an array contains digits from 0 to 100

Upvotes: 2

Views: 231

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110675

Let's create two arrays:

a = [1, 2]
b = [3, 4]

Like all objects, these arrays have unique object ids:

a.object_id  #=> 48242540181360 
b.object_id  #=> 48242540299680 

Now let's add them together:

c = a + b    #=> [1, 2, 3, 4] 

This creates a new object (held by the variable c):

c.object_id  #=> 48242540315060 

and leaves (the objects held by) a and b (and their object ids) unchanged:

a            #=> [1, 2] 
b            #=> [3, 4]

Now, let's write:

a += b       #=> [1, 2, 3, 4]

which Ruby changes to:

a = a + b

when it compiles the code. We obtain:

a            #=> [1, 2, 3, 4] 
a.object_id  #=> 48242541482040

The variable a now holds a new object that equals the previous value of a plus b.

Now let's concatenate b with (the new value of) a:

a.concat(b)  #=> [1, 2, 3, 4, 3, 4]  

This changes (mutates) a, but of course does not change a's object id:

a            #=> [1, 2, 3, 4, 3, 4] 
a.object_id  #=> 48242541482040  

Lastly, we could replace a's value with c, without affecting a's object id:

a.replace(c) #=> [1, 2, 3, 4]
a            #=> [1, 2, 3, 4] 
a.object_id  #=> 48242541482040

See Array#+, Array#concat and Array#replace.

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Unlike Enumerable#reduce, Enumerable#each_with_object passes the same object through reducing process.

Array#+ creates a new instance, leaving the original object unrouched.
Array#concat mutates the original object.

With reduce the result will be the same:

0.step.reduce([]) do |acc, index|
  break acc if index > 100
  acc + [index]
end

Upvotes: 5

Related Questions