Collection::mapWithKeys
Rebuilds a collection from key/value pairs returned by a callback for each item.
public function mapWithKeys(callable $callback): staticParameters
| Parameter | Type | Description |
|---|---|---|
$$callback | callable | Called as ($value, $key); must return an associative array containing a single key => value pair. |
Return value
Illuminate\Support\CollectionA new collection built from the key/value pairs the callback returned.
Errors
The returned pair is iterated with foreach, so returning a scalar instead of an array raises a foreach warning and contributes nothing to the result.
Where map can only change values, mapWithKeys lets the callback decide the key as well. For each item the callback returns a one-element associative array, and those pairs are merged, in order, into the new collection.
When to reach for it
Building lookup tables and option lists: id => name for a select box, email => user for a deduplication pass, code => rate from an exchange-rate feed. Reach for keyBy instead when you want to keep the whole item as the value and only need to choose its key; use this method when the value changes too.
What trips people up
The callback must return an array. Returning the value directly is the single most common mistake and produces an empty or broken result rather than a clear error, because the framework simply iterates over what came back.
Duplicate keys collapse silently — the last pair written wins — so a non-unique key quietly shrinks the collection. And although the docs specify a single pair, the implementation merges every pair in the returned array, so returning several works but is not a documented contract.
Example
When to use it
- Build an id => label array to feed a select box or a validation rule.
- Convert a list of settings rows into a flat key => value config array.
- Key a collection by one field while replacing the value with another.
Frequently asked questions
What must the callback return?
An associative array holding a single key => value pair, such as ['[email protected]' => 'Ada']. Returning a bare value instead of an array is the usual cause of an empty result.
How is it different from keyBy?
keyBy chooses a new key but keeps the whole original item as the value; this method lets you replace the value at the same time.
What happens if two items produce the same key?
The later pair overwrites the earlier one, so the resulting collection is shorter than the input with no warning.
More examples
Settings rows into a flat config array
The three rows collapse into a single associative array keyed by setting name, so lookups no longer need a search. Note that get() treats 'mail.port' as a literal key here, not as dot notation.
<?php
$rows = collect([
['key' => 'mail.driver', 'value' => 'smtp'],
['key' => 'mail.port', 'value' => 587],
['key' => 'app.locale', 'value' => 'en'],
]);
$settings = $rows->mapWithKeys(fn (array $row) => [$row['key'] => $row['value']]);
print_r($settings->all());
echo $settings->get('mail.port') . PHP_EOL;Duplicate keys collapse
Three rows become two entries: 'ada' keeps only the last date, 2024-01-03. That is useful when the input is sorted oldest-first and you want the newest per user, and a silent data loss when it is not.
<?php
$logins = collect([
['user' => 'ada', 'at' => '2024-01-01'],
['user' => 'linus', 'at' => '2024-01-02'],
['user' => 'ada', 'at' => '2024-01-03'],
]);
$latest = $logins->mapWithKeys(fn (array $row) => [$row['user'] => $row['at']]);
print_r($latest->all());
echo 'in: ' . $logins->count() . ' out: ' . $latest->count() . PHP_EOL;Options for a form
The idiomatic way to turn models into a select box's value => label array. It needs a booted application and a database, so it is shown rather than executed here.
<?php
$options = Country::query()
->orderBy('name')
->get()
->mapWithKeys(fn (Country $country) => [$country->iso => $country->name])
->all();
return view('address.form', ['countries' => $options]);
Discussion