Laravel 5 Collections: Mapping Collection Elements and Reducing to a Single Dimension With flatMap

3 min read

The flatMap method is used in the same way as the map method but will collapse the resulting collection.

The flatMap method does not modify the original collection; it will return a new, modified collection its return result.

Signature

1public function flatMap(
2 callable $callback
3);

Example Use

The following two code examples are equivalent:

1<?php
2 
3use Illuminate\Support\Collection;
4 
5// Create a new collection instance.
6$collection = new Collection([
7 'first', 'second', 'third'
8]);
9 
10// Create a new collection where all the strings
11// in the original collection have had their case
12// changed to upper-case.
13$newCollection = $collection->map(function($item, $key) {
14 return strtoupper($item);
15})->collapse();
16 
17 
18// Using the flatMap method
19$newCollection = $collection->flatMap(function($item, $key) {
20 return strtoupper($item);
21});

Using flatMap With Higher Order Messages

The flatMap method can be used with higher order messaging, which allows us to invoke collection methods and access object instance properties using PHP's property accessors syntax.

In the reject and partition sections, we created the following Person class:

app/Person.php:

1use \Illuminate\Contracts\Support\Arrayable;
2 
3class Product implements Arrayable
4{
5 public $name = '';
6 public $price = 0.0;
7 public $onSale = false;
8 
9 /**
10 * Determines if the product is on sale.
11 *
12 * @return bool
13 */
14 public function isOnSale() {
15 return $this->onSale === true;
16 }
17 
18 /**
19 * Determines if the product is not on sale.
20 *
21 * @return bool
22 */
23 public function isNotOnSale() {
24 return !$this->isOnSale();
25 }
26 
27 public function toArray()
28 {
29 return [
30 'name' => $this->name,
31 'price' => $this->price,
32 'onsale' => intval($this->onSale)
33 ];
34 }
35 
36}

We could then create a nested collection of Product instances with the following:

1$products = collect([
2 'products' => [
3 [
4 'name' => 'Office Chair',
5 'price' => 399.99,
6 'onSale' => false
7 ],
8 [
9 'name' => 'Desk',
10 'price' => 199.34,
11 'onSale' => true
12 ]
13 ]
14])->transform(function ($item) {
15 return Collection::wrap($item)->transform(function ($productItem) {
16 $product = new Product;
17 $product->name = $productItem['name'];
18 $product->price = $productItem['price'];
19 $product->onSale = $productItem['onSale'];
20 
21 return $product;
22 });
23});

After the following code has executed, the $products collection would contain a structure similar to the following output:

1Collection {
2 #items: array [
3 "products" => Collection {
4 #items: array [
5 0 => Product {
6 name: "Office Chair"
7 price: 399.99
8 onSale: false
9 }
10 1 => Product {
11 name: "Desk"
12 price: 199.34
13 onSale: true
14 }
15 ]
16 }
17 ]
18}

We could map each of the nested product classes to their array equivalent by invoking each product's toArray method using higher order messaging:

1$flatMapped = $products->flatMap->toArray();

After the above code has executed, the $flatMapped collection would contain a structure similar to the following output:

1Collection {
2 #items: array [
3 0 => array [
4 "name" => "Office Chair"
5 "price" => 399.99
6 "onsale" => 0
7 ]
8 1 => array [
9 "name" => "Desk"
10 "price" => 199.34
11 "onsale" => 1
12 ]
13 ]
14}

Thanks for taking the time to read this post! If you found this article useful and want to help support more work like this, please consider sponsoring my work on GitHub, or by checking out some merch.

 Sponsor on GitHub  Shop Merch