Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Collection Pipelines

Collection Pipelines

An introduction to Collection Pipelines in PHP: dataset transformations as a readable chain of operations.

Avatar for Michael Schmidt-Voigt

Michael Schmidt-Voigt

March 27, 2018

More Decks by Michael Schmidt-Voigt

Other Decks in Programming

Transcript

  1. function getUserEmails($users) { $emails = []; for ($i = 0;

    $i < count($users); $i++) { $user = $users[$i]; if ($user->email !== null) { $emails[] = $user->email; } } return $emails; }
  2. > Declarative programming is a programming paradigm … that *expresses

    the logic of a computation without describing its control flow*.
  3. function getUserEmails($users) { $emails = []; for ($i = 0;

    $i < count($users); $i++) { $user = $users[$i]; if ($user->email !== null) { $emails[] = $user->email; } } return $emails; } SELECT email FROM users WHERE email IS NOT NULL
  4. > a function that takes one or more functions as

    arguments and/or returns a function as its result.
  5. $twice = function($func, $val) { return $func($func($val)); }; $addThree =

    function($val) { return $val + 3; }; echo $twice($addThree, 7); // => 13
  6. $emails = []; foreach ($users as $user) { $emails[] =

    $user->email; } return $emails; $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotals[] = [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; } return $stockTotals;
  7. $emails = []; foreach ($users as $user) { $emails[] =

    $user->email; } return $emails; $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotals[] = [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; } return $stockTotals;
  8. $results = []; foreach ($items as $item) { $result =

    $item->email; $results[] = $result; } return $items; $results = []; foreach ($items as $item) { $result = [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; $results[] = $result; } return $items;
  9. $func = function ($item) { return $item->email; }; $results =

    []; foreach ($items as $item) { $result = $func($item); $results[] = $result; } return $results; $func = function ($item) { return [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; }; $results = []; foreach ($items as $item) { $result = $func($item); $results[] = $result; } return $results;
  10. $func = function ($item) { return $item->email; }; $results =

    []; foreach ($items as $item) { $result = $func($item); $results[] = $result; } return $results; $func = function ($item) { return [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; }; $results = []; foreach ($items as $item) { $result = $func($item); $results[] = $result; } return $results;
  11. function map($items, $func) { $results = []; foreach ($items as

    $item) { $results[] = $func($item); } return $results; }
  12. function map($items, $func) { $results = []; foreach ($items as

    $item) { $results[] = $func($item); } return $results; }
  13. $userEmails = map($users, function ($user) { return $user->email; }); $stockTotals

    = map($inventoryItems, function ($item) { return [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; });
  14. $products = map($productJson, function ($productData) { return new Product($productData); });

    $displayPrices = map($prices, function ($price) { return '$' . number_format($price / 100, 2); });
  15. function filter($items, $func) { $result = []; foreach ($items as

    $item) { if ($func($item)) { $result[] = $item; } } return $result; }
  16. function filter($items, $func) { $result = []; foreach ($items as

    $item) { if ($func($item)) { $result[] = $item; } } return $result; }
  17. $outOfStockProducts = filter($products, function ($product) { return $product->isOutOfStock(); }); $expensiveProducts

    = filter($products, function ($product) { return $product->price > 100; });
  18. $inStockProducts = reject($products, function ($product) { return $product->isOutOfStock(); }); $totalPrice

    = reduce($cart->items, function ($totalPrice, $item) { return $totalPrice + $item->price; }, 0); // ...
  19. function getUserEmails($users) { $emails = []; for ($i = 0;

    $i < count($users); $i++) { $user = $users[$i]; if ($user->email !== null) { $emails[] = $user->email; } } return $emails; } SELECT email FROM users WHERE email IS NOT NULL
  20. function getUserEmails($users) { $emails = []; foreach ($users as $user)

    { if ($user->email !== null) { $emails[] = $user->email; } } return $emails; }
  21. function getUserEmails($users) { $emails = []; foreach ($users as $user)

    { if ($user->email !== null) { $emails[] = $user->email; } } return $emails; }
  22. function getUserEmails($users) { $usersWithEmails = filter($users, function ($user) { return

    $user->email !== null; }); $emails = []; foreach ($usersWithEmails as $user) { $emails[] = $user->email; } return $emails; }
  23. function getUserEmails($users) { $usersWithEmails = filter($users, function ($user) { return

    $user->email !== null; }); return map($usersWithEmails, function ($user) { return $user->email; }); }
  24. function getUserEmails($users) { return array_map(function ($user) { return $user->email; },

    array_filter($users, function ($user) { return $user->email !== null; })); }
  25. function getUserEmails($users) { $usersWithEmails = $users->filter(function ($user) { return $user->email

    !== null; }); return $usersWithEmails->map(function ($user) { return $user->email; }); }
  26. function getUserEmails($users) { return $users ->filter(function ($user) { return $user->email

    !== null; }) ->map(function ($user) { return $user->email; }); }
  27. class Collection { protected $items; public function __construct($items) { $this->items

    = $items; } public function map($callback) { return new static(array_map($callback, $this->items)); } public function filter($callback) { return new static(array_filter($this->items, $callback)); } // ... }
  28. function getUserEmails($users) { return (new Collection($users)) ->filter(function ($user) { return

    $user->email !== null; }) ->map(function ($user) { return $user->email; }) ->toArray(); }
  29. function getUserEmails($users) { return Collection::make($users) ->filter(function ($user) { return $user->email

    !== null; }) ->map(function ($user) { return $user->email; }) ->toArray(); }
  30. $items = Collection::make([1, 2, 3]); echo $items[1]; // => 2

    $items = Collection::make([1, 2, 3]); count($items); $items->count(); // => 3 // => 3 $collection = Collection::make([1, 2, 3]); foreach ($collection as $item) { echo $item; } // => 1 // => 2 // => 3
  31. $average = Collection::make([1, 1, 2, 4])->avg(); // or min(), max(),

    median(), sum() // 2 $chunks = Collection::make([1, 2, 3, 4, 5])->chunk(3); // [[1, 2, 3], [4, 5]] $first = Collection::make([1, 2, 3, 4])->first(); // or last(), nth() // 1 $merged = collect(['product_id' => 1, 'price' => 100]) ->merge(['price' => 200, 'discount' => false]); // ['product_id' => 1, 'price' => 200, 'discount' => false]
  32. $movies = Collection::make([ ['name' => 'Back To the Future', 'genre'

    => 'scifi', 'rating' => 8], ['name' => 'The Matrix', 'genre' => 'fantasy', 'rating' => 9], ['name' => 'The Jungle Book', 'genre' => 'fantasy', 'rating' => 5], ]); $moviesByGenre = $movies->groupBy('genre')->toArray(); /*[ "scifi" => [ ["name" => "Back To the Future", "genre" => "scifi", "rating" => 8,], ], "fantasy" => [ ["name" => "The Matrix", "genre" => "fantasy", "rating" => 9,], ["name" => "The Jungle Book", "genre" => "fantasy", "rating" => 5, ], ] ]*/
  33. $likedPosts = Collection::make($users) ->filter(function ($user) { return $user->verified; }) ->indexBy(function($user)

    { return $user->id; }) ->map(function($user) { return Collection::make($user->posts) ->filter(function($post) { return $post->likes > 3; }); }) ->reject(function($posts) { return isEmpty($posts); });
  34. > all, average, avg, chunk, collapse, combine, concat, contains, containsStrict,

    count, crossJoin, dd, diff, diffAssoc, diffKeys, dump, each, eachSpread, every, except, filter, first, firstWhere, flatMap, flatten, flip, forget, forPage, get, groupBy, has, implode, intersect, intersectByKeys, isEmpty, isNotEmpty, keyBy, keys, last, macro, make, map, mapInto, mapSpread, mapToGroups, mapWithKeys, max, median, merge, min, mode, nth, only, pad, partition, pipe, pluck, pop, prepend, pull, push, put, random, reduce, reject, reverse, search, shift, shuffle, slice, sort, sortBy, sortByDesc, splice, split, sum, take, tap, times, toArray, toJson, transform, union, unique, uniqueStrict, unless, unwrap, values, when, where, whereStrict, whereIn, whereInStrict, whereNotIn, whereNotInStrict, wrap, zip