Skip to content

Jagged Array

Store rows of different lengths as an array of arrays.

A jagged array stores a collection of rows where each row can have a different length. It is usually represented as an array of arrays.

You use it when the data is grouped by row, but each group may contain a different number of elements.

Problem

Given a jagged array AA, support reading and writing an element at row ii and column jj where:

0i<rows(A) 0 \le i < rows(A)

and

0j<length(A[i]) 0 \le j < length(A[i])

Structure

A jagged array stores each row separately:

A=[[8,3,5],[1],[9,4]] A = [ [8, 3, 5], [1], [9, 4] ]

Rows do not need the same length.

Algorithm

Read an element:

get(A, i, j):
    if i < 0 or i >= rows(A):
        error "row index out of bounds"
    if j < 0 or j >= length(A[i]):
        error "column index out of bounds"
    return A[i][j]

Write an element:

set(A, i, j, x):
    if i < 0 or i >= rows(A):
        error "row index out of bounds"
    if j < 0 or j >= length(A[i]):
        error "column index out of bounds"
    A[i][j] = x

Example

Let

A=[[8,3,5],[1],[9,4]] A = [ [8, 3, 5], [1], [9, 4] ]

To read position (2,1)(2, 1):

stepactionresult
1check row02<30 \le 2 < 3
2check column01<20 \le 1 < 2
3read value44

Return 44.

Correctness

The row bounds check ensures that A[i]A[i] exists. The column bounds check ensures that index jj exists inside that specific row. Since each row owns its own storage, reading or writing A[i][j]A[i][j] affects exactly the requested element.

Complexity

operationtime
getO(1)O(1)
setO(1)O(1)
append rowO(1)O(1) amortized
scan all elementsO(m)O(m)

Here mm is the total number of stored elements across all rows.

Space usage:

O(m+r) O(m + r)

where rr is the number of rows.

When to Use

Jagged arrays are appropriate when:

  • rows have different lengths
  • rectangular storage would waste space
  • each row is processed independently
  • adjacency lists or grouped records are needed

They are less suitable when uniform matrix operations or cache-friendly full-row scans dominate.

Implementation

class JaggedArray:
    def __init__(self):
        self.rows = []

    def append_row(self, row):
        self.rows.append(list(row))

    def get(self, i, j):
        if i < 0 or i >= len(self.rows):
            raise IndexError("row index out of bounds")
        if j < 0 or j >= len(self.rows[i]):
            raise IndexError("column index out of bounds")
        return self.rows[i][j]

    def set(self, i, j, x):
        if i < 0 or i >= len(self.rows):
            raise IndexError("row index out of bounds")
        if j < 0 or j >= len(self.rows[i]):
            raise IndexError("column index out of bounds")
        self.rows[i][j] = x
type JaggedArray[T any] struct {
    rows [][]T
}

func (j *JaggedArray[T]) AppendRow(row []T) {
    copied := make([]T, len(row))
    copy(copied, row)
    j.rows = append(j.rows, copied)
}

func (j *JaggedArray[T]) Get(i, k int) (T, bool) {
    var zero T
    if i < 0 || i >= len(j.rows) {
        return zero, false
    }
    if k < 0 || k >= len(j.rows[i]) {
        return zero, false
    }
    return j.rows[i][k], true
}

func (j *JaggedArray[T]) Set(i, k int, x T) bool {
    if i < 0 || i >= len(j.rows) {
        return false
    }
    if k < 0 || k >= len(j.rows[i]) {
        return false
    }
    j.rows[i][k] = x
    return true
}