# `std.ArrayList`

### `std.ArrayList`

`std.ArrayList` is a growable array.

Use it when the number of elements is not known at compile time.

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();

    var list = std.ArrayList(u8).init(allocator);
    defer list.deinit();

    try list.append(10);
    try list.append(20);
    try list.append(30);

    std.debug.print("{any}\n", .{list.items});
}
```

The output is:

```text
{ 10, 20, 30 }
```

An `ArrayList(T)` stores values of type `T`.

```zig
std.ArrayList(u8)
```

This means: a growable array of bytes.

The list owns its memory. It uses the allocator passed to `init`.

```zig
var list = std.ArrayList(u8).init(allocator);
```

When the list is no longer needed, release its memory.

```zig
defer list.deinit();
```

Appending may allocate memory.

For that reason, `append` can fail.

```zig
try list.append(10);
```

The `try` passes the error back to the caller if allocation fails.

Because of this, `main` returns an error union:

```zig
pub fn main() !void
```

The `!void` return type means the function either succeeds with no value or returns an error.

The elements are accessed through the `items` field.

```zig
list.items
```

This field is a slice.

```zig
[]u8
```

You can loop over it like any other slice.

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();

    var list = std.ArrayList(i32).init(allocator);
    defer list.deinit();

    try list.append(3);
    try list.append(5);
    try list.append(8);

    for (list.items) |value| {
        std.debug.print("{d}\n", .{value});
    }
}
```

The output is:

```text
3
5
8
```

`ArrayList` has two important sizes.

The first is the number of elements in use:

```zig
list.items.len
```

The second is the amount of storage reserved internally.

This storage is called capacity.

When there is unused capacity, appending can add an element without allocating.

When the capacity is full, the list allocates a larger buffer and copies the old elements.

You can reserve capacity in advance.

```zig
try list.ensureTotalCapacity(100);
```

This is useful when the final size is roughly known.

An `ArrayList` can also be initialized with existing capacity.

```zig
try list.ensureTotalCapacity(1024);
```

Then many appends can happen without repeated allocation.

To remove all elements but keep the allocation, use:

```zig
list.clearRetainingCapacity();
```

To remove all elements and free the allocation, use:

```zig
list.clearAndFree();
```

The first form is useful when the list will be reused.

The second form is useful when the memory should be returned immediately.

A common pattern is to build a string.

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();

    var buf = std.ArrayList(u8).init(allocator);
    defer buf.deinit();

    try buf.appendSlice("hello");
    try buf.append(' ');
    try buf.appendSlice("zig");

    std.debug.print("{s}\n", .{buf.items});
}
```

The output is:

```text
hello zig
```

`appendSlice` appends many elements.

```zig
try buf.appendSlice("hello");
```

`append` appends one element.

```zig
try buf.append(' ');
```

The list does not add a sentinel byte unless asked.

If C-style string data is needed, make that explicit.

For ordinary Zig string data, `buf.items` is enough.

`ArrayList` also supports ordered removal.

```zig
_ = list.orderedRemove(1);
```

This removes the element at index `1` and shifts later elements left.

It preserves order.

There is also unordered removal.

```zig
_ = list.swapRemove(1);
```

This replaces the removed element with the last element.

It does not preserve order, but it is faster.

Use `orderedRemove` when order matters.

Use `swapRemove` when order does not matter.

Here is a complete example.

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();

    var list = std.ArrayList(i32).init(allocator);
    defer list.deinit();

    try list.appendSlice(&.{ 10, 20, 30, 40 });

    _ = list.orderedRemove(1);

    std.debug.print("{any}\n", .{list.items});
}
```

The output is:

```text
{ 10, 30, 40 }
```

`ArrayList` is simple, but it makes ownership visible.

The allocator is explicit.

Allocation failure is explicit.

The list must be deinitialized.

The stored elements are exposed as a slice.

This makes it easy to pass the data to functions that do not care whether the slice came from an array, an allocation, or a growable list.

Exercise 14-9. Create an `ArrayList(u32)` and append the numbers 1 through 10.

Exercise 14-10. Build a string with `ArrayList(u8)` and `appendSlice`.

Exercise 14-11. Remove an element with `orderedRemove`.

Exercise 14-12. Repeat the removal with `swapRemove` and compare the result.

