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

April 22, 2018 —John Koster

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}

Some absolutely amazing
people

The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.