Question

How to Add One Array to Another in Ruby Without Creating a Nested Array

rubyarraysmultidimensional-array

Question

I want to add the contents of one array to another in Ruby without ending up with a multi-dimensional array.

I tried this:

somearray = ["some", "thing"]
anotherarray = ["another", "thing"]

somearray.push(anotherarray.flatten!)

I expected this result:

["some", "thing", "another", "thing"]

But instead I got:

["some", "thing", nil]

Why does this happen, and what is the correct way to combine arrays in Ruby so the elements are added individually rather than as a nested array?

Short Answer

By the end of this page, you will understand why push and flatten! produced nil, how Ruby array methods behave when combining arrays, and when to use concat, +, push, or the splat operator to get the result you want.

Concept

In Ruby, there is an important difference between:

  • adding an array as one element
  • adding the elements of an array into another array

That difference is the reason beginners often get nested arrays or unexpected nil values.

The key idea

If you do this:

somearray.push(anotherarray)

Ruby treats anotherarray as a single object and adds it as one item:

["some", "thing", ["another", "thing"]]

That creates a nested array.

If you want to add each element individually, use a method designed for that, such as:

somearray.concat(anotherarray)

Result:

["some", "thing", "another", "thing"]

Why flatten! returned nil

The method flatten! modifies an array in place only if a change is needed. If the array is already flat, Ruby returns nil.

So here:

anotherarray.flatten!

Ruby checks anotherarray:

["another", "thing"]

It is already one-dimensional, so no change is made. Because no change was needed, flatten! returns nil.

Then this runs:

somearray.push(nil)

So the result becomes:

["some", "thing", nil]

Why this matters

In real Ruby code, choosing the right array method affects:

  • whether the original array changes
  • whether you get a new array or mutate the existing one
  • whether arrays are nested or merged
  • whether your code unexpectedly inserts nil

Understanding these differences helps prevent bugs in data processing, API code, and everyday collection handling.

Mental Model

Think of an array like a shopping bag.

  • push(item) puts one item into the bag.
  • If that item is another bag, you now have a bag inside a bag.
  • concat(other_bag_contents) empties the contents of the second bag into the first bag.
  • flatten is like opening smaller bags inside the bag and spreading their contents out.

Now imagine flatten! saying:

  • "I only report back with the bag if I had to rearrange something."
  • "If everything was already flat, I return nil."

So when you used push(anotherarray.flatten!), Ruby basically did this:

  • looked at the second bag
  • saw it was already flat
  • returned nil
  • pushed nil into the first bag

That is why you got nil instead of the array elements.

Take Quiz

Syntax and Examples

Common ways to combine arrays in Ruby

1. Use concat to add elements into the same array

a = ["some", "thing"]
b = ["another", "thing"]

a.concat(b)

p a
# ["some", "thing", "another", "thing"]

concat modifies a.


2. Use + to create a new combined array

a = ["some", "thing"]
b = ["another", "thing"]

c = a + b

p c
# ["some", "thing", "another", "thing"]

This does not modify a or b.


3. Use push to add one item

a = ["some", "thing"]
b = ["another", "thing"]

a.push(b)

p a
# ["some", "thing", ["another", "thing"]]

This creates a nested array because b is added as a single element.


4. Use splat with push to add multiple items

a = ["some", "thing"]
b = ["another", "thing"]

a.push(*b)

p a
# ["some", "thing", "another", "thing"]

The * operator expands the array into separate arguments.


5. flatten vs flatten!

a = ["another", ["thing"]]

p a.flatten
# ["another", "thing"]

p a
# ["another", ["thing"]]

flatten returns a new flattened array.

a = ["another", ["thing"]]

p a.flatten!
# ["another", "thing"]

p a
# ["another", "thing"]

flatten! changes the original array.

If no flattening is needed:

a = ["another", "thing"]

p a.flatten!
# nil

That nil is what caused the problem in the original code.

Step by Step Execution

Consider this code:

somearray = ["some", "thing"]
anotherarray = ["another", "thing"]

somearray.push(anotherarray.flatten!)

Step 1: Create somearray

somearray = ["some", "thing"]

Current value:

["some", "thing"]

Step 2: Create anotherarray

anotherarray = ["another", "thing"]

Current value:

["another", "thing"]

Step 3: Evaluate anotherarray.flatten!

anotherarray.flatten!

Ruby checks whether anotherarray contains nested arrays.

It does not:

["another", "thing"]

So no change is needed.

When flatten! makes no change, it returns:

nil

Step 4: Execute push(nil)

Because anotherarray.flatten! returned nil, this becomes:

somearray.push(nil)

Now somearray is:

["some", "thing", nil]

Correct version using concat

somearray = ["some", "thing"]
anotherarray = ["another", "thing"]

somearray.concat(anotherarray)

p somearray
# ["some", "thing", "another", "thing"]

Step-by-step for concat

  1. Ruby looks at anotherarray
  2. It takes each element from that array
  3. It appends them to somearray
  4. The result is one flat array

Correct version using +

somearray = ["some", "thing"]
anotherarray = ["another", "thing"]

combined = somearray + anotherarray

p combined
# ["some", "thing", "another", "thing"]

Here Ruby creates a new array instead of changing the original one.

Real World Use Cases

Arrays are combined constantly in Ruby applications.

Building a list of tags

default_tags = ["ruby", "backend"]
user_tags = ["api", "json"]

all_tags = default_tags + user_tags

Combining validation errors

errors = []
errors.concat(name_errors)
errors.concat(email_errors)

Merging search results

results = []
results.concat(products)
results.concat(categories)

Collecting CLI arguments

base_args = ["--verbose"]
extra_args = ["--output", "report.txt"]

args = base_args + extra_args

Processing API data

all_records = []
all_records.concat(page_1_records)
all_records.concat(page_2_records)

In each case, you need to decide whether:

  • you want to mutate the original array with concat
  • or create a new array with +
Take Quiz

Real Codebase Usage

In real projects, developers choose array-combining methods based on intent.

Use concat when mutation is intentional

items = []
items.concat(load_defaults)
items.concat(load_user_items)

This is common when building up one array over time.

Use + when you want immutability

final_roles = default_roles + extra_roles

This is clearer when you want to keep the original arrays unchanged.

Use guard clauses before combining

return [] if records.nil?

Or:

items.concat(new_items) if new_items

This helps avoid errors when values may be nil.

Use splat for method arguments

params = ["name", "email"]
log_fields(*params)

The splat operator is useful when a method expects separate values rather than an array.

Common pattern: collect then flatten later

Sometimes developers intentionally build nested arrays and flatten them once:

groups = []
groups << admin_users
groups << guest_users

all_users = groups.flatten

This can be useful, but only when nested arrays are expected.

Error prevention pattern

Avoid destructive methods like flatten! inside other method calls if you depend on their return value:

# Risky
somearray.push(anotherarray.flatten!)

# Clearer
flat = anotherarray.flatten
somearray.concat(flat)

That version is easier to read and safer.

Common Mistakes

1. Using push when you mean concat

Broken code:

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

a.push(b)
p a
# [1, 2, [3, 4]]

Why it happens:

  • push adds b as one element

Fix:

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

2. Expecting flatten! to always return an array

Broken code:

a = [1, 2]
p a.flatten!
# nil

Why it happens:

  • flatten! returns nil when nothing changes

Fix:

p a.flatten
# [1, 2]

Use flatten if you always want an array returned.


3. Accidentally mutating the original array

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

a.concat(b)

If you expected a to stay unchanged, this is a bug.

Fix:

c = a + b

4. Confusing << with adding multiple values

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

p a
# [1, 2, [3, 4]]

<< behaves like adding one item.

Fix:

a.concat([3, 4])

5. Calling methods on nil

Broken code:

a.concat(maybe_array)

If maybe_array is nil, this can fail.

Safer approach:

a.concat(maybe_array || [])

6. Flattening when it is not needed

Some beginners write:

a.concat(b.flatten)

If b is already flat, flatten is unnecessary.

Use the simplest code that matches the structure you already have.

Comparisons

MethodWhat it doesModifies original?Nested array risk?Typical use
push(obj)Adds one object to the endYesYesAdd a single item
<< objSame basic idea as push for one itemYesYesShort form for adding one item
concat(array)Adds each element of another arrayYesNoMerge into existing array
a + bReturns a new combined arrayNoNoNon-destructive combination
flattenReturns a new flattened arrayNoNoRemove nesting in a new array
flatten!Flattens in place if neededYesNoDestructive flattening

concat vs +

Featureconcat+
Changes original arrayYesNo
Returns combined valuesYesYes
Good for building up one arrayYesSometimes
Good for immutable styleNoYes

push vs concat

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

p a.push(b)
# [1, 2, [3, 4]]

p [1, 2].concat(b)
# [1, 2, 3, 4]

Use push for one item. Use concat for another array's elements.

Take Quiz

Cheat Sheet

Quick reference

Add one item

array.push(item)
array << item

Add all elements from another array

array.concat(other_array)

Create a new combined array

new_array = array1 + array2

Expand array into separate arguments

array.push(*other_array)

Flatten nested arrays

flat = array.flatten      # new array
array.flatten!            # modifies original, may return nil

Important rules

  • push adds one object
  • concat adds elements from another array
  • + returns a new array
  • flatten! returns nil if no changes were made
  • << can create nested arrays if you append an array

Safe choices

  • Want to mutate? Use concat
  • Want a new array? Use +
  • Want guaranteed return value while flattening? Use flatten, not flatten!

FAQ

How do I append one array to another in Ruby without nesting?

Use concat or +:

a.concat(b)
# or
c = a + b

Why does flatten! return nil in Ruby?

flatten! returns nil when the array was already flat and Ruby did not need to change anything.

What is the difference between push and concat in Ruby?

push adds one object as a single element. concat adds each element from another array.

Does + modify the original array in Ruby?

No. + creates and returns a new array.

Is << the same as concat?

No. << adds one item. If that item is an array, you get a nested array.

When should I use flatten instead of flatten!?

Use flatten when you want a new flattened array and a guaranteed array return value.

Can I use push(*other_array) in Ruby?

Yes. The splat operator expands the second array into separate values, so push receives multiple items instead of one array.

Take Quiz

Mini Project

Description

Build a small Ruby script that combines task lists from two sources: a default list and a user-provided list. This project demonstrates the difference between adding one array as a single item and merging array elements correctly.

Goal

Create a Ruby program that merges two task arrays into one flat list without nesting.

Requirements

  • Create one array of default tasks.
  • Create one array of extra tasks.
  • Combine them into a single flat array.
  • Print the final merged task list.
  • Show at least one incorrect approach and then the correct one.
Take Quiz

Keep learning

Related questions

View more