Skip to main content
One of ListCollection’s most powerful features is the ability to chain multiple operations together. Every operation maintains sequential numeric indices, making chaining predictable and safe.

Basic Chaining

ListCollection methods return new ListCollection instances, allowing you to chain operations:
$list = new ListCollection([5, 3, 1, 4, 2, 3, 5]);

$result = $list
    ->filter(fn (int $v): bool => $v > 1)
    ->unique()
    ->sort();

// Result: [0 => 2, 1 => 3, 2 => 4, 3 => 5]
Each operation:
  1. filter() removes values ≤ 1 → [5, 3, 4, 2, 3, 5]
  2. unique() removes duplicates → [5, 3, 4, 2]
  3. sort() sorts ascending → [2, 3, 4, 5]
  4. Keys are sequential at every step: [0, 1, 2, 3]
Unlike standard Laravel Collections, ListCollection automatically maintains sequential keys after each operation, eliminating the need to call values() at the end.

Filter, Transform, Sort Pipeline

Combine filtering, transformation, and sorting:
$list = new ListCollection([
    ['active' => true, 'name' => 'Charlie', 'score' => 85],
    ['active' => false, 'name' => 'Alice', 'score' => 92],
    ['active' => true, 'name' => 'Bob', 'score' => 78],
    ['active' => true, 'name' => 'Diana', 'score' => 95],
]);

$result = $list
    ->where('active', true)
    ->sortByDesc('score')
    ->pluck('name');

// Result: [0 => 'Diana', 1 => 'Charlie', 2 => 'Bob']

Map and Flatten

Transform elements and flatten the result:
$list = new ListCollection([1, 2, 3]);

$result = $list
    ->map(fn (int $v): array => [$v, $v * 10])
    ->flatten();

// Result: [0 => 1, 1 => 10, 2 => 2, 3 => 20, 4 => 3, 5 => 30]
Or use flatMap() as a shortcut:
$list = new ListCollection([1, 2, 3]);

$result = $list->flatMap(fn (int $v): array => [$v, $v * 10]);

// Result: [0 => 1, 1 => 10, 2 => 2, 3 => 20, 4 => 3, 5 => 30]

Complex Multi-Step Transformations

Build sophisticated data pipelines:
$list = new ListCollection([
    ['category' => 'A', 'items' => [1, 2, 3]],
    ['category' => 'B', 'items' => [4, 5]],
    ['category' => 'A', 'items' => [6]],
]);

$result = $list
    ->where('category', 'A')
    ->pluck('items')
    ->flatten()
    ->filter(fn (int $v): bool => $v > 2)
    ->sort();

// Result: [0 => 3, 1 => 6]
Step by step:
  1. Filter for category ‘A’ → 2 items
  2. Extract ‘items’ arrays → [[1, 2, 3], [6]]
  3. Flatten to single level → [1, 2, 3, 6]
  4. Keep values > 2 → [3, 6]
  5. Sort ascending → [3, 6] with keys [0, 1]

Chaining Mutating Operations

Some methods modify the original collection and return $this, allowing continued chaining:
$list = new ListCollection(['a', 'b', 'c']);

$list
    ->push('d')
    ->prepend('z')
    ->forget(2);

// List: [0 => 'z', 1 => 'a', 2 => 'c', 3 => 'd']
Be careful when chaining methods like forget() - indices are re-indexed after each call:
$list = new ListCollection(['a', 'b', 'c', 'd']);

$list->forget(1); // removes 'b' → [0 => 'a', 1 => 'c', 2 => 'd']
$list->forget(1); // removes 'c' at NEW index 1 → [0 => 'a', 1 => 'd']

Subset and Transform

Combine subsetting with transformations:
$list = new ListCollection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$result = $list
    ->skip(2)
    ->take(5)
    ->map(fn (int $v): int => $v * 2)
    ->filter(fn (int $v): bool => $v > 10);

// Result: [0 => 12, 1 => 14]
Breakdown:
  1. Skip first 2 → [3, 4, 5, 6, 7, 8, 9, 10]
  2. Take 5 → [3, 4, 5, 6, 7]
  3. Multiply by 2 → [6, 8, 10, 12, 14]
  4. Filter > 10 → [12, 14] with keys [0, 1]

Conditional Processing

Use conditional methods in chains:
$list = new ListCollection([1, 2, 3, 4, 5, 6, 7, 8]);

$result = $list
    ->skipWhile(fn (int $v): bool => $v < 3)
    ->takeUntil(fn (int $v): bool => $v > 6)
    ->map(fn (int $v): int => $v ** 2);

// Result: [0 => 9, 1 => 16, 2 => 25, 3 => 36]

Partition and Process

Split data and process each part:
$list = new ListCollection([1, 2, 3, 4, 5, 6]);

[$even, $odd] = $list->partition(fn (int $v): bool => $v % 2 === 0);

$evenSquared = $even->map(fn (int $v): int => $v ** 2);
$oddDoubled = $odd->map(fn (int $v): int => $v * 2);

// $evenSquared: [0 => 4, 1 => 16, 2 => 36]
// $oddDoubled: [0 => 2, 1 => 6, 2 => 10]

Working with Nested Data

Chain operations on nested structures:
$list = new ListCollection([
    ['users' => [['name' => 'Alice'], ['name' => 'Bob']]],
    ['users' => [['name' => 'Charlie']]],
    ['users' => [['name' => 'Diana'], ['name' => 'Eve']]],
]);

$result = $list
    ->pluck('users')
    ->flatten(1)
    ->pluck('name')
    ->filter(fn (string $name): bool => strlen($name) > 3)
    ->sort();

// Result: [0 => 'Alice', 1 => 'Charlie', 2 => 'Diana']

Combining Set Operations

Chain set-based operations:
$list1 = new ListCollection([1, 2, 3, 4, 5]);
$list2 = [2, 4, 6, 8];
$list3 = [4, 5, 6, 7];

$result = $list1
    ->diff($list2)
    ->merge($list3)
    ->unique()
    ->sort();

// Result: [0 => 1, 1 => 3, 2 => 4, 3 => 5, 4 => 6, 5 => 7]
Step by step:
  1. Diff removes 2, 4 → [1, 3, 5]
  2. Merge adds list3 → [1, 3, 5, 4, 5, 6, 7]
  3. Unique removes duplicates → [1, 3, 5, 4, 6, 7]
  4. Sort ascending → [1, 3, 4, 5, 6, 7]

Chunk and Process

Process data in chunks:
$list = new ListCollection(range(1, 10));

$result = $list
    ->chunk(3)
    ->map(fn (ListCollection $chunk): int => $chunk->sum())
    ->filter(fn (int $sum): bool => $sum > 10);

// Result: [0 => 12, 1 => 15, 2 => 24]
Breakdown:
  1. Chunk into groups of 3 → [[1,2,3], [4,5,6], [7,8,9], [10]]
  2. Sum each chunk → [6, 15, 24, 10]
  3. Keep sums > 10 → [15, 24] with keys re-indexed to [0, 1]

Best Practices

Performance: Chain operations efficiently by placing filtering operations early to reduce the dataset size before expensive transformations.
// Good: Filter first, then transform
$result = $list
    ->filter(fn ($item): bool => $item['active'])
    ->map(fn ($item): array => $this->expensiveTransform($item));

// Less efficient: Transform everything, then filter
$result = $list
    ->map(fn ($item): array => $this->expensiveTransform($item))
    ->filter(fn ($item): bool => $item['active']);
Readability: Break long chains into multiple lines for better readability:
$result = $list
    ->where('active', true)
    ->sortByDesc('priority')
    ->take(10)
    ->pluck('name');
Type Safety: ListCollection maintains type safety through the chain - every operation returns a ListCollection with sequential keys.

Build docs developers (and LLMs) love