NumPy
Python
array manipulation
append
data structures

How do I create an empty array and then append to it in NumPy?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

While you can create an empty NumPy array with np.empty() or np.array([]) and append to it with np.append(), this pattern is almost always wrong because NumPy arrays have fixed sizes — every np.append() creates a new array and copies all data. The recommended approach is to build a Python list first, then convert to a NumPy array at the end. Alternatively, pre-allocate an array with np.zeros() or np.empty() if you know the final size.

The Append Anti-Pattern (Avoid This)

python
1import numpy as np
2
3# SLOW — creates a new array on every append, O(n^2) total
4arr = np.array([])
5for i in range(10000):
6    arr = np.append(arr, i)
7
8print(arr.shape)  # (10000,)

Each np.append() allocates a new array of size n+1 and copies all existing elements. For 10,000 elements, this copies a total of ~50 million elements.

python
1import numpy as np
2
3# FAST — list append is O(1) amortized, conversion is O(n)
4values = []
5for i in range(10000):
6    values.append(i)
7
8arr = np.array(values)
9print(arr.shape)  # (10000,)

This is the standard pattern. Python lists are designed for dynamic appending, while NumPy arrays are designed for fixed-size numerical computation.

With 2D Data

python
1rows = []
2for i in range(100):
3    row = [i, i * 2, i * 3]
4    rows.append(row)
5
6matrix = np.array(rows)
7print(matrix.shape)  # (100, 3)

If you know the final size, pre-allocate and fill by index:

python
1import numpy as np
2
3n = 10000
4arr = np.zeros(n)  # Pre-allocate with zeros
5
6for i in range(n):
7    arr[i] = i * 2.5
8
9print(arr[:5])  # [0.  2.5  5.  7.5  10. ]
python
1# Pre-allocate a 2D array
2rows, cols = 100, 3
3matrix = np.empty((rows, cols))  # Uninitialized (faster than zeros)
4
5for i in range(rows):
6    matrix[i] = [i, i ** 2, i ** 3]
7
8print(matrix.shape)  # (100, 3)

np.empty() is slightly faster than np.zeros() because it does not initialize the memory, but the values are garbage until you write to them.

Creating Empty Arrays

np.empty — Uninitialized

python
1# Creates array with arbitrary (garbage) values
2arr = np.empty((3, 4))
3print(arr)  # Contains whatever was in memory
4
5# Specify dtype
6arr = np.empty(5, dtype=np.int32)

np.zeros — Filled with Zeros

python
1arr = np.zeros(5)
2print(arr)  # [0. 0. 0. 0. 0.]
3
4matrix = np.zeros((3, 4), dtype=np.int32)
5print(matrix)
6# [[0 0 0 0]
7#  [0 0 0 0]
8#  [0 0 0 0]]

np.array([]) — Truly Empty

python
1arr = np.array([])
2print(arr.shape)  # (0,)
3print(arr.dtype)  # float64
4
5# Empty with specific dtype
6arr = np.array([], dtype=np.int32)

Using np.append (When Necessary)

np.append() returns a new array — it does not modify the original:

python
1arr = np.array([1, 2, 3])
2result = np.append(arr, 4)
3print(result)  # [1 2 3 4]
4print(arr)     # [1 2 3] — unchanged!
5
6# Append multiple values
7result = np.append(arr, [4, 5, 6])
8print(result)  # [1 2 3 4 5 6]

Appending Rows to a 2D Array

python
1matrix = np.array([[1, 2], [3, 4]])
2new_row = np.array([[5, 6]])
3
4result = np.append(matrix, new_row, axis=0)
5print(result)
6# [[1 2]
7#  [3 4]
8#  [5 6]]

np.concatenate and np.vstack

For combining existing arrays, np.concatenate is more explicit than np.append:

python
1a = np.array([1, 2, 3])
2b = np.array([4, 5, 6])
3c = np.array([7, 8, 9])
4
5# Concatenate multiple arrays at once (one copy)
6result = np.concatenate([a, b, c])
7print(result)  # [1 2 3 4 5 6 7 8 9]
8
9# Stack rows vertically
10rows = [np.array([1, 2]), np.array([3, 4]), np.array([5, 6])]
11matrix = np.vstack(rows)
12print(matrix)
13# [[1 2]
14#  [3 4]
15#  [5 6]]

Performance Comparison

python
1import numpy as np
2import time
3
4n = 100000
5
6# Method 1: np.append in loop (SLOW)
7start = time.time()
8arr = np.array([])
9for i in range(n):
10    arr = np.append(arr, i)
11print(f"np.append loop: {time.time() - start:.3f}s")
12# ~5-10 seconds
13
14# Method 2: Python list + convert (FAST)
15start = time.time()
16lst = []
17for i in range(n):
18    lst.append(i)
19arr = np.array(lst)
20print(f"List + convert: {time.time() - start:.3f}s")
21# ~0.02 seconds
22
23# Method 3: Pre-allocate (FASTEST)
24start = time.time()
25arr = np.empty(n)
26for i in range(n):
27    arr[i] = i
28print(f"Pre-allocate: {time.time() - start:.3f}s")
29# ~0.01 seconds

Common Pitfalls

  • Using np.append() in a loop: Every call copies the entire array, resulting in O(n^2) time complexity. Build a Python list and convert with np.array() at the end, or pre-allocate with np.zeros()/np.empty().
  • Assuming np.append() modifies in place: Unlike list.append(), np.append() returns a new array. The original is unchanged. You must assign the result: arr = np.append(arr, value).
  • Forgetting axis parameter in 2D append: Without axis, np.append() flattens both arrays into 1D. Use axis=0 to append rows or axis=1 to append columns.
  • Using np.empty() without initializing all elements: np.empty() contains garbage values from memory. If you skip some indices, those positions contain unpredictable data. Use np.zeros() or np.full() if you need a default value.
  • Creating arrays with mismatched dtypes: Appending a float to an int array converts the entire array to float. Specify dtype at creation time to avoid unexpected type promotions.

Summary

  • Avoid np.append() in loops — it copies the entire array each time, making it O(n^2)
  • Build a Python list with list.append(), then convert to NumPy with np.array(lst) at the end
  • Pre-allocate with np.zeros(n) or np.empty(n) and fill by index when the size is known
  • Use np.concatenate() or np.vstack() to combine multiple existing arrays in one operation
  • np.append() returns a new array — it does not modify the original

Course illustration
Course illustration

All Rights Reserved.