markrogoyski / itertools-php
Iteration tools for PHP
Installs: 2 393
Dependents: 1
Suggesters: 0
Security: 0
Stars: 140
Watchers: 5
Forks: 11
Open Issues: 1
Requires
- php: >=7.4.0
Requires (Dev)
- mikey179/vfsstream: ^1.6
- php-coveralls/php-coveralls: ^2.0
- php-parallel-lint/php-parallel-lint: ^1.3
- phploc/phploc: *
- phpmd/phpmd: ^2.10
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^9.0
- squizlabs/php_codesniffer: 3.*
- vimeo/psalm: ^5.11
This package is auto-updated.
Last update: 2024-10-28 04:54:06 UTC
README
IterTools - PHP Iteration Tools to Power Up Your Loops
Inspired by Python—designed for PHP.
Features
IterTools makes you an iteration superstar by providing two types of tools:
- Loop iteration tools
- Stream iteration tools
Loop Iteration Tools Example
foreach (Multi::zip(['a', 'b'], [1, 2]) as [$letter, $number]) { print($letter . $number); // a1, b2 }
Stream Iteration Tools Example
$result = Stream::of([1, 1, 2, 2, 3, 4, 5]) ->distinct() // [1, 2, 3, 4, 5] ->map(fn ($x) => $x**2) // [1, 4, 9, 16, 25] ->filter(fn ($x) => $x < 10) // [1, 4, 9] ->toSum(); // 14
All functions work on iterable
collections:
array
(type)Generator
(type)Iterator
(interface)Traversable
(interface)
README docs translated in other languages:
Quick Reference
Loop Iteration Tools
Multi Iteration
Single Iteration
Infinite Iteration
Random Iteration
Math Iteration
Set and multiset Iteration
Sort Iteration
File Iteration
Transform Iteration
Summary
Reduce
Stream Iteration Tools
Stream Sources
Stream Operations
Stream Terminal Operations
Summary Terminal Operations
Reduction Terminal Operations
Transformation Terminal Operations
Side Effect Terminal Operations
Stream Debug Operations
Setup
Add the library to your composer.json
file in your project:
{ "require": { "markrogoyski/itertools-php": "1.*" } }
Use composer to install the library:
$ php composer.phar install
Composer will install IterTools inside your vendor folder. Then you can add the following to your .php files to use the library with Autoloading.
require_once __DIR__ . '/vendor/autoload.php';
Alternatively, use composer on the command line to require and install IterTools:
$ php composer.phar require markrogoyski/itertools-php:1.*
Minimum Requirements
- PHP 7.4
Usage
All functions work on iterable
collections:
array
(type)Generator
(type)Iterator
(interface)Traversable
(interface)
Multi Iteration
Chain
Chain multiple iterables together into a single continuous sequence.
Multi::chain(iterable ...$iterables)
use IterTools\Multi; $prequels = ['Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith']; $originals = ['A New Hope', 'Empire Strikes Back', 'Return of the Jedi']; foreach (Multi::chain($prequels, $originals) as $movie) { print($movie); } // 'Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith', 'A New Hope', 'Empire Strikes Back', 'Return of the Jedi'
Zip
Iterate multiple iterable collections simultaneously.
Multi::zip(iterable ...$iterables)
use IterTools\Multi; $languages = ['PHP', 'Python', 'Java', 'Go']; $mascots = ['elephant', 'snake', 'bean', 'gopher']; foreach (Multi::zip($languages, $mascots) as [$language, $mascot]) { print("The {$language} language mascot is an {$mascot}."); } // The PHP language mascot is an elephant. // ...
Zip works with multiple iterable inputs--not limited to just two.
$names = ['Ryu', 'Ken', 'Chun Li', 'Guile']; $countries = ['Japan', 'USA', 'China', 'USA']; $signatureMoves = ['hadouken', 'shoryuken', 'spinning bird kick', 'sonic boom']; foreach (Multi::zip($names, $countries, $signatureMoves) as [$name, $country, $signatureMove]) { $streetFighter = new StreetFighter($name, $country, $signatureMove); }
Note: For uneven lengths, iteration stops when the shortest iterable is exhausted.
ZipEqual
Iterate multiple iterable collections with equal lengths simultaneously.
Throws \LengthException
if lengths are not equal, meaning that at least one iterator ends before the others.
Multi::zipEqual(iterable ...$iterables)
use IterTools\Multi; $letters = ['A', 'B', 'C']; $numbers = [1, 2, 3]; foreach (Multi::zipEqual($letters, $numbers) as [$letter, $number]) { // ['A', 1], ['B', 2], ['C', 3] }
ZipFilled
Iterate multiple iterable collections simultaneously, using a default filler value if lengths are not equal.
Multi::zipFilled(mixed $filler, iterable ...$iterables)
use IterTools\Multi; $default = '?'; $letters = ['A', 'B']; $numbers = [1, 2, 3]; foreach (Multi::zipFilled($default, $letters, $numbers) as [$letter, $number]) { // ['A', 1], ['B', 2], ['?', 3] }
ZipLongest
Iterate multiple iterable collections simultaneously.
Multi::zipLongest(iterable ...$iterables)
For uneven lengths, the exhausted iterables will produce null
for the remaining iterations.
use IterTools\Multi; $letters = ['A', 'B', 'C']; $numbers = [1, 2]; foreach (Multi::zipLongest($letters, $numbers) as [$letter, $number]) { // ['A', 1], ['B', 2], ['C', null] }
Single Iteration
Chunkwise
Return elements in chunks of a certain size.
Single::chunkwise(iterable $data, int $chunkSize)
Chunk size must be at least 1.
use IterTools\Single; $movies = [ 'Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith', 'A New Hope', 'Empire Strikes Back', 'Return of the Jedi', 'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker' ]; foreach (Single::chunkwise($movies, 3) as $trilogy) { $trilogies[] = $trilogy; } // [ // ['Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith'], // ['A New Hope', 'Empire Strikes Back', 'Return of the Jedi'], // ['The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker]' // ]
Chunkwise Overlap
Return overlapped chunks of elements.
Single::chunkwiseOverlap(iterable $data, int $chunkSize, int $overlapSize, bool $includeIncompleteTail = true)
- Chunk size must be at least 1.
- Overlap size must be less than chunk size.
use IterTools\Single; $numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; foreach (Single::chunkwiseOverlap($numbers, 3, 1) as $chunk) { // [1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10] }
Compress
Compress an iterable by filtering out data that is not selected.
Single::compress(string $data, $selectors)
use IterTools\Single; $movies = [ 'Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith', 'A New Hope', 'Empire Strikes Back', 'Return of the Jedi', 'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker' ]; $goodMovies = [0, 0, 0, 1, 1, 1, 1, 0, 0]; foreach (Single::compress($movies, $goodMovies) as $goodMovie) { print($goodMovie); } // 'A New Hope', 'Empire Strikes Back', 'Return of the Jedi', 'The Force Awakens'
Compress Associative
Compress an iterable by filtering out keys that are not selected.
Single::compressAssociative(string $data, array $selectorKeys)
- Standard PHP array/iterator keys only (string, integer).
use IterTools\Single; $starWarsEpisodes = [ 'I' => 'The Phantom Menace', 'II' => 'Attack of the Clones', 'III' => 'Revenge of the Sith', 'IV' => 'A New Hope', 'V' => 'The Empire Strikes Back', 'VI' => 'Return of the Jedi', 'VII' => 'The Force Awakens', 'VIII' => 'The Last Jedi', 'IX' => 'The Rise of Skywalker', ]; $originalTrilogyNumbers = ['IV', 'V', 'VI']; foreach (Single::compressAssociative($starWarsEpisodes, $originalTrilogyNumbers) as $episode => $title) { print("$episode: $title" . \PHP_EOL); } // IV: A New Hope // V: The Empire Strikes Back // VI: Return of the Jedi
Drop While
Drop elements from the iterable while the predicate function is true.
Once the predicate function returns false once, all remaining elements are returned.
Single::dropWhile(iterable $data, callable $predicate)
use IterTools\Single; $scores = [50, 60, 70, 85, 65, 90]; $predicate = fn ($x) => $x < 70; foreach (Single::dropWhile($scores, $predicate) as $score) { print($score); } // 70, 85, 65, 90
Filter
Filter out elements from the iterable only returning elements where the predicate function is true.
Single::filter(iterable $data, callable $predicate)
use IterTools\Single; $starWarsEpisodes = [1, 2, 3, 4, 5, 6, 7, 8, 9]; $goodMoviePredicate = fn ($episode) => $episode > 3 && $episode < 8; foreach (Single::filter($starWarsEpisodes, $goodMoviePredicate) as $goodMovie) { print($goodMovie); } // 4, 5, 6, 7
Filter True
Filter out elements from the iterable only returning elements that are truthy.
Single::filterTrue(iterable $data)
use IterTools\Single; $reportCardGrades = [100, 0, 95, 85, 0, 94, 0]; foreach (Single::filterTrue($reportCardGrades) as $goodGrade) { print($goodGrade); } // 100, 95, 85, 94
Filter False
Filter out elements from the iterable only returning elements where the predicate function is false.
If no predicate is provided, the boolean value of the data is used.
Single::filterFalse(iterable $data, callable $predicate)
use IterTools\Single; $alerts = [0, 1, 1, 0, 1, 0, 0, 1, 1]; foreach (Single::filterFalse($alerts) as $noAlert) { print($noAlert); } // 0, 0, 0, 0
Filter Keys
Filter out elements from the iterable only returning elements for which keys the predicate function is true.
Single::filterKeys(iterable $data, callable $predicate)
use IterTools\Single; $olympics = [ 2000 => 'Sydney', 2002 => 'Salt Lake City', 2004 => 'Athens', 2006 => 'Turin', 2008 => 'Beijing', 2010 => 'Vancouver', 2012 => 'London', 2014 => 'Sochi', 2016 => 'Rio de Janeiro', 2018 => 'Pyeongchang', 2020 => 'Tokyo', 2022 => 'Beijing', ]; $summerFilter = fn ($year) => $year % 4 === 0; foreach (Single::filterKeys($olympics, $summerFilter) as $year => $hostCity) { print("$year: $hostCity" . \PHP_EOL); } // 2000: Sydney // 2004: Athens // 2008: Beijing // 2012: London // 2016: Rio de Janeiro // 2020: Tokyo
Flat Map
Map a function only the elements of the iterable and then flatten the results.
Single::flatMap(iterable $data, callable $mapper)
use IterTools\Single; $data = [1, 2, 3, 4, 5]; $mapper = fn ($item) => [$item, -$item]; foreach (Single::flatMap($data, $mapper) as $number) { print($number . ' '); } // 1 -1 2 -2 3 -3 4 -4 5 -5
Flatten
Flatten a multidimensional iterable.
Single::flatten(iterable $data, int $dimensions = 1)
use IterTools\Single; $multidimensional = [1, [2, 3], [4, 5]]; $flattened = []; foreach (Single::flatten($multidimensional) as $number) { $flattened[] = $number; } // [1, 2, 3, 4, 5]
Group By
Group data by a common data element.
Single::groupBy(iterable $data, callable $groupKeyFunction, callable $itemKeyFunction = null)
- The
$groupKeyFunction
determines the key to group elements by. - The optional
$itemKeyFunction
allows custom indexes within each group member.
use IterTools\Single; $cartoonCharacters = [ ['Garfield', 'cat'], ['Tom', 'cat'], ['Felix', 'cat'], ['Heathcliff', 'cat'], ['Snoopy', 'dog'], ['Scooby-Doo', 'dog'], ['Odie', 'dog'], ['Donald', 'duck'], ['Daffy', 'duck'], ]; $charactersGroupedByAnimal = []; foreach (Single::groupBy($cartoonCharacters, fn ($x) => $x[1]) as $animal => $characters) { $charactersGroupedByAnimal[$animal] = $characters; } /* 'cat' => [ ['Garfield', 'cat'], ['Tom', 'cat'], ['Felix', 'cat'], ['Heathcliff', 'cat'], ], 'dog' => [ ['Snoopy', 'dog'], ['Scooby-Doo', 'dog'], ['Odie', 'dog'], ], 'duck' => [ ['Donald', 'duck'], ['Daffy', 'duck'], */
Limit
Iterate up to a limit.
Stops even if more data available if limit reached.
Single::limit(iterable $data, int $limit)
use IterTools\Single; $matrixMovies = ['The Matrix', 'The Matrix Reloaded', 'The Matrix Revolutions', 'The Matrix Resurrections']; $limit = 1; foreach (Single::limit($matrixMovies, $limit) as $goodMovie) { print($goodMovie); } // 'The Matrix' (and nothing else)
Map
Map a function onto each element.
Single::map(iterable $data, callable $function)
use IterTools\Single; $grades = [100, 99, 95, 98, 100]; $strictParentsOpinion = fn ($g) => $g === 100 ? 'A' : 'F'; foreach (Single::map($grades, $strictParentsOpinion) as $actualGrade) { print($actualGrade); } // A, F, F, F, A
Pairwise
Returns successive overlapping pairs.
Returns empty generator if given collection contains fewer than 2 elements.
Single::pairwise(iterable $data)
use IterTools\Single; $friends = ['Ross', 'Rachel', 'Chandler', 'Monica', 'Joey', 'Phoebe']; foreach (Single::pairwise($friends) as [$leftFriend, $rightFriend]) { print("{$leftFriend} and {$rightFriend}"); } // Ross and Rachel, Rachel and Chandler, Chandler and Monica, ...
Repeat
Repeat an item.
Single::repeat(mixed $item, int $repetitions)
use IterTools\Single; $data = 'Beetlejuice'; $repetitions = 3; foreach (Single::repeat($data, $repetitions) as $repeated) { print($repeated); } // 'Beetlejuice', 'Beetlejuice', 'Beetlejuice'
Reindex
Reindex keys of key-value iterable using indexer function.
Single::reindex(string $data, callable $indexer)
use IterTools\Single; $data = [ [ 'title' => 'Star Wars: Episode IV – A New Hope', 'episode' => 'IV', 'year' => 1977, ], [ 'title' => 'Star Wars: Episode V – The Empire Strikes Back', 'episode' => 'V', 'year' => 1980, ], [ 'title' => 'Star Wars: Episode VI – Return of the Jedi', 'episode' => 'VI', 'year' => 1983, ], ]; $reindexFunc = fn (array $swFilm) => $swFilm['episode']; $reindexedData = []; foreach (Single::reindex($data, $reindexFunc) as $key => $filmData) { $reindexedData[$key] = $filmData; } // [ // 'IV' => [ // 'title' => 'Star Wars: Episode IV – A New Hope', // 'episode' => 'IV', // 'year' => 1977, // ], // 'V' => [ // 'title' => 'Star Wars: Episode V – The Empire Strikes Back', // 'episode' => 'V', // 'year' => 1980, // ], // 'VI' => [ // 'title' => 'Star Wars: Episode VI – Return of the Jedi', // 'episode' => 'VI', // 'year' => 1983, // ], // ]
Reverse
Reverse the elements of an iterable.
Single::reverse(iterable $data)
use IterTools\Single; $words = ['Alice', 'answers', 'your', 'questions', 'Bob']; foreach (Single::reverse($words) as $word) { print($word . ' '); } // Bob questions your answers Alice
Skip
Skip n elements in the iterable after optional offset offset.
Single::skip(iterable $data, int $count, int $offset = 0)
use IterTools\Single; $movies = [ 'The Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith', 'A New Hope', 'The Empire Strikes Back', 'Return of the Jedi', 'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker' ]; $prequelsRemoved = []; foreach (Single::skip($movies, 3) as $nonPrequel) { $prequelsRemoved[] = $nonPrequel; } // Episodes IV - IX $onlyTheBest = []; foreach (Single::skip($prequelsRemoved, 3, 3) as $nonSequel) { $onlyTheBest[] = $nonSequel; } // 'A New Hope', 'The Empire Strikes Back', 'Return of the Jedi'
Slice
Extract a slice of the iterable.
Single::slice(iterable $data, int $start = 0, int $count = null, int $step = 1)
use IterTools\Single; $olympics = [1992, 1994, 1996, 1998, 2000, 2002, 2004, 2006, 2008, 2010, 2012, 2014, 2016, 2018, 2020, 2022]; $winterOlympics = []; foreach (Single::slice($olympics, 1, 8, 2) as $winterYear) { $winterOlympics[] = $winterYear; } // [1994, 1998, 2002, 2006, 2010, 2014, 2018, 2022]
String
Iterate the individual characters of a string.
Single::string(string $string)
use IterTools\Single; $string = 'MickeyMouse'; $listOfCharacters = []; foreach (Single::string($string) as $character) { $listOfCharacters[] = $character; } // ['M', 'i', 'c', 'k', 'e', 'y', 'M', 'o', 'u', 's', 'e']
Take While
Return elements from the iterable as long as the predicate is true.
Stops iteration as soon as the predicate returns false, even if other elements later on would eventually return true (different from filterTrue).
Single::takeWhile(iterable $data, callable $predicate)
use IterTools\Single; $prices = [0, 0, 5, 10, 0, 0, 9]; $isFree = fn ($price) => $price == 0; foreach (Single::takeWhile($prices, $isFree) as $freePrice) { print($freePrice); } // 0, 0
Infinite Iteration
Count
Count sequentially forever.
Infinite::count(int $start = 1, int $step = 1)
use IterTools\Infinite; $start = 1; $step = 1; foreach (Infinite::count($start, $step) as $i) { print($i); } // 1, 2, 3, 4, 5 ...
Cycle
Cycle through the elements of a collection sequentially forever.
Infinite::cycle(iterable $iterable)
use IterTools\Infinite; $hands = ['rock', 'paper', 'scissors']; foreach (Infinite::cycle($hands) as $hand) { RockPaperScissors::playHand($hand); } // rock, paper, scissors, rock, paper, scissors, ...
Repeat (Infinite)
Repeat an item forever.
Infinite::repeat(mixed $item)
use IterTools\Infinite; $dialogue = 'Are we there yet?'; foreach (Infinite::repeat($dialogue) as $repeated) { print($repeated); } // 'Are we there yet?', 'Are we there yet?', 'Are we there yet?', ...
Random Iteration
Choice
Generate random selections from an array of values.
Random::choice(array $items, int $repetitions)
use IterTools\Random; $cards = ['Ace', 'King', 'Queen', 'Jack', 'Joker']; $repetitions = 10; foreach (Random::choice($cards, $repetitions) as $card) { print($card); } // 'King', 'Jack', 'King', 'Ace', ... [random]
CoinFlip
Generate random coin flips (0 or 1).
Random::coinFlip(int $repetitions)
use IterTools\Random; $repetitions = 10; foreach (Random::coinFlip($repetitions) as $coinFlip) { print($coinFlip); } // 1, 0, 1, 1, 0, ... [random]
Number
Generate random numbers (integers).
Random::number(int $min, int $max, int $repetitions)
use IterTools\Random; $min = 1; $max = 4; $repetitions = 10; foreach (Random::number($min, $max, $repetitions) as $number) { print($number); } // 3, 2, 5, 5, 1, 2, ... [random]
Percentage
Generate a random percentage between 0 and 1.
Random::percentage(int $repetitions)
use IterTools\Random; $repetitions = 10; foreach (Random::percentage($repetitions) as $percentage) { print($percentage); } // 0.30205562629132, 0.59648594775233, ... [random]
RockPaperScissors
Generate random rock-paper-scissors hands.
Random::rockPaperScissors(int $repetitions)
use IterTools\Random; $repetitions = 10; foreach (Random::rockPaperScissors($repetitions) as $rpsHand) { print($rpsHand); } // 'paper', 'rock', 'rock', 'scissors', ... [random]
Math Iteration
Frequencies
Returns a frequency distribution of the data.
Math::frequencies(iterable $data, bool $strict = true): \Generator
Defaults to strict type comparisons. Set strict to false for type coercion comparisons.
use IterTools\Math; $grades = ['A', 'A', 'B', 'B', 'B', 'C']; foreach (Math::frequencies($grades) as $grade => $frequency) { print("$grade: $frequency" . \PHP_EOL); } // A: 2, B: 3, C: 1
Relative Frequencies
Returns a relative frequency distribution of the data.
Math::relativeFrequencies(iterable $data, bool $strict = true): \Generator
Defaults to strict type comparisons. Set strict to false for type coercion comparisons.
use IterTools\Math; $grades = ['A', 'A', 'B', 'B', 'B', 'C']; foreach (Math::relativeFrequencies($grades) as $grade => $frequency) { print("$grade: $frequency" . \PHP_EOL); } // A: 0.33, B: 0.5, C: 0.166
Running Average
Accumulate the running average over a list of numbers.
Math::runningAverage(iterable $numbers, int|float $initialValue = null)
use IterTools\Math; $grades = [100, 80, 80, 90, 85]; foreach (Math::runningAverage($grades) as $runningAverage) { print($runningAverage); } // 100, 90, 86.667, 87.5, 87
Running Difference
Accumulate the running difference over a list of numbers.
Math::runningDifference(iterable $numbers, int|float $initialValue = null)
use IterTools\Math; $credits = [1, 2, 3, 4, 5]; foreach (Math::runningDifference($credits) as $runningDifference) { print($runningDifference); } // -1, -3, -6, -10, -15
Provide an optional initial value to lead off the running difference.
use IterTools\Math; $dartsScores = [50, 50, 25, 50]; $startingScore = 501; foreach (Math::runningDifference($dartsScores, $startingScore) as $runningScore) { print($runningScore); } // 501, 451, 401, 376, 326
Running Max
Accumulate the running maximum over a list of numbers.
Math::runningMax(iterable $numbers, int|float $initialValue = null)
use IterTools\Math; $numbers = [1, 2, 1, 3, 5]; foreach (Math::runningMax($numbers) as $runningMax) { print($runningMax); } // 1, 2, 2, 3, 5
Running Min
Accumulate the running minimum over a list of numbers.
Math::runningMin(iterable $numbers, int|float $initialValue = null)
use IterTools\Math; $numbers = [3, 4, 2, 5, 1]; foreach (Math::runningMin($numbers) as $runningMin) { print($runningMin); } // 3, 3, 2, 2, 1
Running Product
Accumulate the running product over a list of numbers.
Math::runningProduct(iterable $numbers, int|float $initialValue = null)
use IterTools\Math; $numbers = [1, 2, 3, 4, 5]; foreach (Math::runningProduct($numbers) as $runningProduct) { print($runningProduct); } // 1, 2, 6, 24, 120
Provide an optional initial value to lead off the running product.
use IterTools\Math; $numbers = [1, 2, 3, 4, 5]; $initialValue = 5; foreach (Math::runningProduct($numbers, $initialValue) as $runningProduct) { print($runningProduct); } // 5, 5, 10, 30, 120, 600
Running Total
Accumulate the running total over a list of numbers.
Math::runningTotal(iterable $numbers, int|float $initialValue = null)
use IterTools\Math; $prices = [1, 2, 3, 4, 5]; foreach (Math::runningTotal($prices) as $runningTotal) { print($runningTotal); } // 1, 3, 6, 10, 15
Provide an optional initial value to lead off the running total.
use IterTools\Math; $prices = [1, 2, 3, 4, 5]; $initialValue = 5; foreach (Math::runningTotal($prices, $initialValue) as $runningTotal) { print($runningTotal); } // 5, 6, 8, 11, 15, 20
Set and Multiset
Distinct
Filter out elements from the iterable only returning distinct elements.
Set::distinct(iterable $data, bool $strict = true)
Defaults to strict type comparisons. Set strict to false for type coercion comparisons.
use IterTools\Set; $chessSet = ['rook', 'rook', 'knight', 'knight', 'bishop', 'bishop', 'king', 'queen', 'pawn', 'pawn', ... ]; foreach (Set::distinct($chessSet) as $chessPiece) { print($chessPiece); } // rook, knight, bishop, king, queen, pawn $mixedTypes = [1, '1', 2, '2', 3]; foreach (Set::distinct($mixedTypes, false) as $datum) { print($datum); } // 1, 2, 3
Distinct By
Filter out elements from the iterable only returning distinct elements according to a custom comparator function.
Set::distinctBy(iterable $data, callable $compareBy)
use IterTools\Set; $streetFighterConsoleReleases = [ ['id' => '112233', 'name' => 'Street Fighter 3 3rd Strike', 'console' => 'Dreamcast'], ['id' => '223344', 'name' => 'Street Fighter 3 3rd Strike', 'console' => 'PS4'], ['id' => '334455', 'name' => 'Street Fighter 3 3rd Strike', 'console' => 'PS5'], ['id' => '445566', 'name' => 'Street Fighter VI', 'console' => 'PS4'], ['id' => '556677', 'name' => 'Street Fighter VI', 'console' => 'PS5'], ['id' => '667788', 'name' => 'Street Fighter VI', 'console' => 'PC'], ]; $compareBy = fn ($sfTitle) => $sfTitle['name']; $uniqueTitles = []; foreach (Set::distinctBy($streetFighterConsoleReleases, $compareBy) as $sfTitle) { $uniqueTitles[] = $sfTitle; } // Contains one SF3 3rd Strike entry and one SFVI entry.
Intersection
Iterates intersection of iterables.
Set::intersection(iterable ...$iterables)
If input iterables produce duplicate items, then multiset intersection rules apply.
use IterTools\Set; $chessPieces = ['rook', 'knight', 'bishop', 'queen', 'king', 'pawn']; $shogiPieces = ['rook', 'knight', 'bishop' 'king', 'pawn', 'lance', 'gold general', 'silver general']; foreach (Set::intersection($chessPieces, $shogiPieces) as $commonPiece) { print($commonPiece); } // rook, knight, bishop, king, pawn
Intersection Coercive
Iterates intersection of iterables using type coercion.
Set::intersectionCoercive(iterable ...$iterables)
If input iterables produce duplicate items, then multiset intersection rules apply.
use IterTools\Set; $numbers = [1, 2, 3, 4, 5]; $numerics = ['1', '2', 3]; foreach (Set::intersectionCoercive($numbers, $numerics) as $commonNumber) { print($commonNumber); } // 1, 2, 3
Partial Intersection
Iterates M-partial intersection of iterables.
Set::partialIntersection(int $minIntersectionCount, iterable ...$iterables)
- If input iterables produce duplicate items, then multiset intersection rules apply.
use IterTools\Set; $staticallyTyped = ['c++', 'java', 'c#', 'go', 'haskell']; $dynamicallyTyped = ['php', 'python', 'javascript', 'typescript']; $supportsInterfaces = ['php', 'java', 'c#', 'typescript']; foreach (Set::partialIntersection(2, $staticallyTyped, $dynamicallyTyped, $supportsInterfaces) as $language) { print($language); } // c++, java, c#, go, php
Partial Intersection Coercive
Iterates M-partial intersection of iterables using type coercion.
Set::partialIntersectionCoercive(int $minIntersectionCount, iterable ...$iterables)
- If input iterables produce duplicate items, then multiset intersection rules apply.
use IterTools\Set; $set1 = [1, 2, 3], $set2 = ['2', '3', 4, 5], $set3 = [1, '2'], foreach (Set::partialIntersectionCoercive(2, $set1, $set2, $set3) as $partiallyCommonNumber) { print($partiallyCommonNumber); } // 1, 2, 3
Symmetric difference
Iterates the symmetric difference of iterables.
Set::symmetricDifference(iterable ...$iterables)
If input iterables produce duplicate items, then multiset difference rules apply.
use IterTools\Set; $a = [1, 2, 3, 4, 7]; $b = ['1', 2, 3, 5, 8]; $c = [1, 2, 3, 6, 9]; foreach (Set::symmetricDifference($a, $b, $c) as $item) { print($item); } // 1, 4, 5, 6, 7, 8, 9
Symmetric difference Coercive
Iterates the symmetric difference of iterables with type coercion.
Set::symmetricDifferenceCoercive(iterable ...$iterables)
If input iterables produce duplicate items, then multiset difference rules apply.
use IterTools\Set; $a = [1, 2, 3, 4, 7]; $b = ['1', 2, 3, 5, 8]; $c = [1, 2, 3, 6, 9]; foreach (Set::symmetricDifferenceCoercive($a, $b, $c) as $item) { print($item); } // 4, 5, 6, 7, 8, 9
Union
Iterates the union of iterables.
Set::union(iterable ...$iterables)
If input iterables produce duplicate items, then multiset union rules apply.
use IterTools\Set; $a = [1, 2, 3]; $b = [3, 4]; $c = [1, 2, 3, 6, 7]; foreach (Set::union($a, $b, $c) as $item) { print($item); } //1, 2, 3, 4, 6, 7
Union Coercive
Iterates the union of iterables with type coercion.
Set::unionCoercive(iterable ...$iterables)
If input iterables produce duplicate items, then multiset union rules apply.
use IterTools\Set; $a = ['1', 2, 3]; $b = [3, 4]; $c = [1, 2, 3, 6, 7]; foreach (Set::unionCoercive($a, $b, $c) as $item) { print($item); } //1, 2, 3, 4, 6, 7
Sort Iteration
ASort
Iterate the collection sorted while maintaining the associative key index relations.
Sort::sort(iterable $data, callable $comparator = null)
Uses default sorting if optional comparator function not provided.
use IterTools\Single; $worldPopulations = [ 'China' => 1_439_323_776, 'India' => 1_380_004_385, 'Indonesia' => 273_523_615, 'Pakistan' => 220_892_340, 'USA' => 331_002_651, ]; foreach (Sort::sort($worldPopulations) as $country => $population) { print("$country: $population" . \PHP_EOL); } // Pakistan: 220,892,340 // Indonesia: 273,523,615 // USA: 331,002,651 // India: 1,380,004,385 // China: 1,439,323,776
Sort
Iterate the collection sorted.
Sort::sort(iterable $data, callable $comparator = null)
Uses default sorting if optional comparator function not provided.
use IterTools\Single; $data = [3, 4, 5, 9, 8, 7, 1, 6, 2]; foreach (Sort::sort($data) as $datum) { print($datum); } // 1, 2, 3, 4, 5, 6, 7, 8, 9
File
Read CSV
Iterate the lines of a CSV file.
File::readCsv(resource $fileHandle, string $separator = ',', string $enclosure = '"', string $escape = '\\')
use IterTools\File; $fileHandle = \fopen('path/to/file.csv', 'r'); foreach (File::readCsv($fileHandle) as $row) { print_r($row); } // Each column field is an element of the array
Read Lines
Iterate the lines of a file.
File::readLines(resource $fileHandle)
use IterTools\File; $fileHandle = \fopen('path/to/file.txt', 'r'); foreach (File::readLines($fileHandle) as $line) { print($line); }
Transform
Tee
Return several independent (duplicated) iterators from a single iterable.
Transform::tee(iterable $data, int $count): array
use IterTools\Transform; $daysOfWeek = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun']; $count = 3; [$week1, $week2, $week3] = Transform::tee($data, $count); // Each $week contains iterator containing ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun']
To Array
Transforms any iterable to an array.
Transform::toArray(iterable $data): array
use IterTools\Transform; $iterator = new \ArrayIterator([1, 2, 3, 4, 5]); $array = Transform::toArray($iterator);
To Associative Array
Transforms any iterable to an associative array.
Transform::toAssociativeArray(iterable $data, callable $keyFunc = null, callable $valueFunc = null): array
use IterTools\Transform; $messages = ['message 1', 'message 2', 'message 3']; $keyFunc = fn ($msg) => \md5($msg); $valueFunc = fn ($msg) => strtoupper($msg); $associativeArray = Transform::toAssociativeArray($messages, $keyFunc, $valueFunc); // [ // '1db65a6a0a818fd39655b95e33ada11d' => 'MESSAGE 1', // '83b2330607fe8f817ce6d24249dea373' => 'MESSAGE 2', // '037805d3ad7b10c5b8425427b516b5ce' => 'MESSAGE 3', // ]
To Iterator
Transforms any iterable to an iterator.
Transform::toArray(iterable $data): array
use IterTools\Transform; $array = [1, 2, 3, 4, 5]; $iterator = Transform::toIterator($array);
Summary
All Match
Returns true if all elements match the predicate function.
Summary::allMatch(iterable $data, callable $predicate): bool
use IterTools\Summary; $finalFantasyNumbers = [4, 5, 6]; $isOnSuperNintendo = fn ($ff) => $ff >= 4 && $ff <= 6; $boolean = Summary::allMatch($finalFantasyNumbers, $isOnSuperNintendo); // true $isOnPlaystation = fn ($ff) => $ff >= 7 && $ff <= 9; $boolean = Summary::allMatch($finalFantasyNumbers, $isOnPlaystation); // false
All Unique
Returns true if all elements are unique.
Summary::allUnique(iterable $data, bool $strict = true): bool
Defaults to strict type comparisons. Set strict to false for type coercion comparisons.
use IterTools\Summary; $items = ['fingerprints', 'snowflakes', 'eyes', 'DNA'] $boolean = Summary::allUnique($items); // true
Any Match
Returns true if any element matches the predicate function.
Summary::anyMatch(iterable $data, callable $predicate): bool
use IterTools\Summary; $answers = ['fish', 'towel', 42, "don't panic"]; $isUltimateAnswer = fn ($a) => a == 42; $boolean = Summary::anyMatch($answers, $isUltimateAnswer); // true
Are Permutations
Returns true if all iterables are permutations of each other.
Summary::arePermutations(iterable ...$iterables): bool
use IterTools\Summary; $iter = ['i', 't', 'e', 'r']; $rite = ['r', 'i', 't', 'e']; $reit = ['r', 'e', 'i', 't']; $tier = ['t', 'i', 'e', 'r']; $tire = ['t', 'i', 'r', 'e']; $trie = ['t', 'r', 'i', 'e']; $boolean = Summary::arePermutations($iter, $rite, $reit, $tier, $tire, $trie); // true
Are Permutations Coercive
Returns true if all iterables are permutations of each other with type coercion.
Summary::arePermutationsCoercive(iterable ...$iterables): bool
use IterTools\Summary; $set1 = [1, 2.0, '3']; $set2 = [2.0, '1', 3]; $set3 = [3, 2, 1]; $boolean = Summary::arePermutationsCoercive($set1, $set2, $set3); // true
Exactly N
Returns true if exactly n items are true according to a predicate function.
- Predicate is optional.
- Default predicate is boolean value of each item.
Summary::exactlyN(iterable $data, int $n, callable $predicate): bool
use IterTools\Summary; $twoTruthsAndALie = [true, true, false]; $n = 2; $boolean = Summary::exactlyN($twoTruthsAndALie, $n); // true $ages = [18, 21, 24, 54]; $n = 4; $predicate = fn ($age) => $age >= 21; $boolean = Summary::exactlyN($ages, $n, $predicate); // false
Is Empty
Returns true if the iterable is empty having no items.
Summary::isEmpty(iterable $data): bool
use IterTools\Summary; $data = [] $boolean = Summary::isEmpty($data); // true
Is Partitioned
Returns true if all elements of given collection that satisfy the predicate appear before all elements that don't.
- Returns true for empty collection or for collection with single item.
- Default predicate if not provided is the boolean value of each data item.
Summary::isPartitioned(iterable $data, callable $predicate = null): bool
use IterTools\Summary; $numbers = [0, 2, 4, 1, 3, 5]; $evensBeforeOdds = fn ($item) => $item % 2 === 0; $boolean = Summary::isPartitioned($numbers, $evensBeforeOdds);
Is Sorted
Returns true if elements are sorted, otherwise false.
- Elements must be comparable.
- Returns true if empty or has only one element.
Summary::isSorted(iterable $data): bool
use IterTools\Summary; $numbers = [1, 2, 3, 4, 5]; $boolean = Summary::isSorted($numbers); // true $numbers = [3, 2, 3, 4, 5]; $boolean = Summary::isSorted($numbers); // false
Is Reversed
Returns true if elements are reverse sorted, otherwise false.
- Elements must be comparable.
- Returns true if empty or has only one element.
Summary::isReversed(iterable $data): bool
use IterTools\Summary; $numbers = [5, 4, 3, 2, 1]; $boolean = Summary::isReversed($numbers); // true $numbers = [1, 4, 3, 2, 1]; $boolean = Summary::isReversed($numbers); // false
None Match
Returns true if no element matches the predicate function.
Summary::noneMatch(iterable $data, callable $predicate): bool
use IterTools\Summary; $grades = [45, 50, 61, 0]; $isPassingGrade = fn ($grade) => $grade >= 70; $boolean = Summary::noneMatch($grades, $isPassingGrade); // true
Same
Returns true if all given collections are the same.
For single iterable or empty iterables list returns true.
Summary::same(iterable ...$iterables): bool
use IterTools\Summary; $cocaColaIngredients = ['carbonated water', 'sugar', 'caramel color', 'phosphoric acid']; $pepsiIngredients = ['carbonated water', 'sugar', 'caramel color', 'phosphoric acid']; $boolean = Summary::same($cocaColaIngredients, $pepsiIngredients); // true $cocaColaIngredients = ['carbonated water', 'sugar', 'caramel color', 'phosphoric acid']; $spriteIngredients = ['carbonated water', 'sugar', 'citric acid', 'lemon lime flavorings']; $boolean = Summary::same($cocaColaIngredients, $spriteIngredients); // false
Same Count
Returns true if all given collections have the same lengths.
For single iterable or empty iterables list returns true.
Summary::sameCount(iterable ...$iterables): bool
use IterTools\Summary; $prequels = ['Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith']; $originals = ['A New Hope', 'Empire Strikes Back', 'Return of the Jedi']; $sequels = ['The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker']; $boolean = Summary::sameCount($prequels, $originals, $sequels); // true $batmanMovies = ['Batman Begins', 'The Dark Knight', 'The Dark Knight Rises']; $matrixMovies = ['The Matrix', 'The Matrix Reloaded', 'The Matrix Revolutions', 'The Matrix Resurrections']; $result = Summary::sameCount($batmanMovies, $matrixMovies); // false
Reduce
To Average
Reduces to the mean average.
Returns null if collection is empty.
Reduce::toAverage(iterable $data): float
use IterTools\Reduce; $grades = [100, 90, 95, 85, 94]; $finalGrade = Reduce::toAverage($numbers); // 92.8
To Count
Reduces iterable to its length.
Reduce::toCount(iterable $data): int
use IterTools\Reduce; $someIterable = ImportantThing::getCollectionAsIterable(); $length = Reduce::toCount($someIterable); // 3
To First
Reduces iterable to its first element.
Reduce::toFirst(iterable $data): mixed
Throws \LengthException
if collection is empty.
use IterTools\Reduce; $medals = ['gold', 'silver', 'bronze']; $first = Reduce::toFirst($medals); // gold
To First And Last
Reduces iterable to its first and last elements.
Reduce::toFirstAndLast(iterable $data): array{mixed, mixed}
Throws \LengthException
if collection is empty.
use IterTools\Reduce; $weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']; $firstAndLast = Reduce::toFirstAndLast($weekdays); // [Monday, Friday]
To Last
Reduces iterable to its last element.
Reduce::toLast(iterable $data): mixed
Throws \LengthException
if collection is empty.
use IterTools\Reduce; $gnomesThreePhasePlan = ['Collect underpants', '?', 'Profit']; $lastPhase = Reduce::toLast($gnomesThreePhasePlan); // Profit
To Max
Reduces to the max value.
Reduce::toMax(iterable $data, callable $compareBy = null): mixed|null
- Optional callable param
$compareBy
must return comparable value. - If
$compareBy
is not provided then items of given collection must be comparable. - Returns null if collection is empty.
use IterTools\Reduce; $numbers = [5, 3, 1, 2, 4]; $result = Reduce::toMax($numbers); // 5 $movieRatings = [ [ 'title' => 'Star Wars: Episode IV - A New Hope', 'rating' => 4.6 ], [ 'title' => 'Star Wars: Episode V - The Empire Strikes Back', 'rating' => 4.8 ], [ 'title' => 'Star Wars: Episode VI - Return of the Jedi', 'rating' => 4.6 ], ]; $compareBy = fn ($movie) => $movie['rating']; $highestRatedMovie = Reduce::toMax($movieRatings, $compareBy); // [ // 'title' => 'Star Wars: Episode V - The Empire Strikes Back', // 'rating' => 4.8 // ];
To Min
Reduces to the min value.
Reduce::toMin(iterable $data, callable $compareBy = null): mixed|null
- Optional callable param
$compareBy
must return comparable value. - If
$compareBy
is not provided then items of given collection must be comparable. - Returns null if collection is empty.
use IterTools\Reduce; $numbers = [5, 3, 1, 2, 4]; $result = Reduce::toMin($numbers); // 1 $movieRatings = [ [ 'title' => 'The Matrix', 'rating' => 4.7 ], [ 'title' => 'The Matrix Reloaded', 'rating' => 4.3 ], [ 'title' => 'The Matrix Revolutions', 'rating' => 3.9 ], [ 'title' => 'The Matrix Resurrections', 'rating' => 2.5 ], ]; $compareBy = fn ($movie) => $movie['rating']; $lowestRatedMovie = Reduce::toMin($movieRatings, $compareBy); // [ // 'title' => 'The Matrix Resurrections', // 'rating' => 2.5 // ]
To Min Max
Reduces to array of its upper and lower bounds (max and min).
Reduce::toMinMax(iterable $numbers, callable $compareBy = null): array
- Optional callable param
$compareBy
must return comparable value. - If
$compareBy
is not provided then items of given collection must be comparable. - Returns
[null, null]
if given collection is empty.
use IterTools\Reduce; $numbers = [1, 2, 7, -1, -2, -3]; [$min, $max] = Reduce::toMinMax($numbers); // [-3, 7] $reportCard = [ [ 'subject' => 'history', 'grade' => 90 ], [ 'subject' => 'math', 'grade' => 98 ], [ 'subject' => 'science', 'grade' => 92 ], [ 'subject' => 'english', 'grade' => 85 ], [ 'subject' => 'programming', 'grade' => 100 ], ]; $compareBy = fn ($class) => $class['grade']; $bestAndWorstSubject = Reduce::toMinMax($reportCard, $compareBy); // [ // [ // 'subject' => 'english', // 'grade' => 85 // ], // [ // 'subject' => 'programming', // 'grade' => 100 // ], // ]
To Nth
Reduces to value at the nth position.
Reduce::toNth(iterable $data, int $position): mixed
use IterTools\Reduce; $lotrMovies = ['The Fellowship of the Ring', 'The Two Towers', 'The Return of the King']; $rotk = Reduce::toNth($lotrMovies, 2); // 20
To Product
Reduces to the product of its elements.
Returns null if collection is empty.
Reduce::toProduct(iterable $data): number|null
use IterTools\Reduce; $primeFactors = [5, 2, 2]; $number = Reduce::toProduct($primeFactors); // 20
To Random Value
Reduces given collection to a random value within it.
Reduce::toRandomValue(iterable $data): mixed
use IterTools\Reduce; $sfWakeupOptions = ['mid', 'low', 'overhead', 'throw', 'meaty']; $wakeupOption = Reduce::toRandomValue($sfWakeupOptions); // e.g., throw
To Range
Reduces given collection to its range (difference between max and min).
Reduce::toRange(iterable $numbers): int|float
Returns 0
if iterable source is empty.
use IterTools\Reduce; $grades = [100, 90, 80, 85, 95]; $range = Reduce::toRange($numbers); // 20
To String
Reduces to a string joining all elements.
- Optional separator to insert between items.
- Optional prefix to prepend to the string.
- Optional suffix to append to the string.
Reduce::toString(iterable $data, string $separator = '', string $prefix = '', string $suffix = ''): string
use IterTools\Reduce; $words = ['IterTools', 'PHP', 'v1.0']; $string = Reduce::toString($words); // IterToolsPHPv1.0 $string = Reduce::toString($words, '-'); // IterTools-PHP-v1.0 $string = Reduce::toString($words, '-', 'Library: '); // Library: IterTools-PHP-v1.0 $string = Reduce::toString($words, '-', 'Library: ', '!'); // Library: IterTools-PHP-v1.0!
To Sum
Reduces to the sum of its elements.
Reduce::toSum(iterable $data): number
use IterTools\Reduce; $parts = [10, 20, 30]; $sum = Reduce::toSum($parts); // 60
To Value
Reduce elements to a single value using reducer function.
Reduce::toValue(iterable $data, callable $reducer, mixed $initialValue): mixed
use IterTools\Reduce; $input = [1, 2, 3, 4, 5]; $sum = fn ($carry, $item) => $carry + $item; $result = Reduce::toValue($input, $sum, 0); // 15
Stream
Streams provide a fluent interface to transform arrays and iterables through a pipeline of operations.
Streams are made up of:
- One stream source factory method to create the stream.
- Zero or more stream operators that transform the stream to a new stream.
- Terminal operation of either:
- Stream terminal operation to transform the stream to a value or data structure.
$result = Stream::of([1, 1, 2, 2, 3, 4, 5]) ->distinct() // [1, 2, 3, 4, 5] ->map(fn ($x) => $x**2) // [1, 4, 9, 16, 25] ->filter(fn ($x) => $x < 10) // [1, 4, 9] ->toSum(); // 14
- The stream is iterated via a
foreach
loop.
$result = Stream::of([1, 1, 2, 2, 3, 4, 5]) ->distinct() // [1, 2, 3, 4, 5] ->map(fn ($x) => $x**2) // [1, 4, 9, 16, 25] ->filter(fn ($x) => $x < 10); // [1, 4, 9] foreach ($result as $item) { // 1, 4, 9 }
Stream Sources
Of
Creates stream from an iterable.
Stream::of(iterable $iterable): Stream
use IterTools\Stream; $iterable = [1, 2, 3]; $result = Stream::of($iterable) ->chainWith([4, 5, 6], [7, 8, 9]) ->zipEqualWith([1, 2, 3, 4, 5, 6, 7, 8, 9]) ->toValue(fn ($carry, $item) => $carry + array_sum($item)); // 90
Of Coin Flips
Creates stream of n random coin flips.
Stream::ofCoinFlips(int $repetitions): Stream
use IterTools\Stream; $result = Stream::ofCoinFlips(10) ->filterTrue() ->toCount(); // 5 (random)
Of CSV File
Creates a stream of rows of a CSV file.
Stream::ofCsvFile(resource $fileHandle, string $separator = ',', string $enclosure = '"', string = $escape = '\\'): Stream
use IterTools\Stream; $fileHandle = \fopen('path/to/file.csv', 'r'); $result = Stream::of($fileHandle) ->toArray();
Of Empty
Creates stream of nothing.
Stream::ofEmpty(): Stream
use IterTools\Stream; $result = Stream::ofEmpty() ->chainWith([1, 2, 3]) ->toArray(); // 1, 2, 3
Of File Lines
Creates a stream of lines of a file.
Stream::ofFileLines(resource $fileHandle): Stream
use IterTools\Stream; $fileHandle = \fopen('path/to/file.txt', 'r'); $result = Stream::of($fileHandle) ->map('strtoupper'); ->toArray();
Of Random Choice
Creates stream of random selections from an array of values.
Stream::ofRandomChoice(array $items, int $repetitions): Stream
use IterTools\Stream; $languages = ['PHP', 'Go', 'Python']; $languages = Stream::ofRandomChoice($languages, 5) ->toArray(); // 'Go', 'PHP', 'Python', 'PHP', 'PHP' (random)
Of Random Numbers
Creates stream of random numbers (integers).
Stream::ofRandomNumbers(int $min, int $max, int $repetitions): Stream
use IterTools\Stream; $min = 1; $max = 3; $reps = 7; $result = Stream::ofRandomNumbers($min, $max, $reps) ->toArray(); // 1, 2, 2, 1, 3, 2, 1 (random)
Of Random Percentage
Creates stream of random percentages between 0 and 1.
Stream::ofRandomPercentage(int $repetitions): Stream
use IterTools\Stream; $stream = Stream::ofRandomPercentage(3) ->toArray(); // 0.8012566976245, 0.81237281724151, 0.61676896329459 [random]
Of Range
Creates stream of a range of numbers.
Stream::ofRange(int|float $start, int|float $end, int|float $step = 1): Stream
use IterTools\Stream; $numbers = Stream::ofRange(0, 5) ->toArray(); // 0, 1, 2, 3, 4, 5
Of Rock Paper Scissors
Creates stream of rock-paper-scissors hands.
Stream::ofRockPaperScissors(int $repetitions): Stream
use IterTools\Stream; $rps = Stream::ofRockPaperScissors(5) ->toArray(); // 'paper', 'rock', 'rock', 'scissors', 'paper' [random]
Stream Operations
ASort
Sorts the stream, maintaining keys.
$stream->asort(callable $comparator = null)
If comparator is not provided, the elements of the iterable source must be comparable.
use IterTools\Stream; $worldPopulations = [ 'China' => 1_439_323_776, 'India' => 1_380_004_385, 'Indonesia' => 273_523_615, 'USA' => 331_002_651, ]; $result = Stream::of($worldPopulations) ->filter(fn ($pop) => $pop > 300_000_000) ->asort() ->toAssociativeArray(); // USA => 331_002_651, // India => 1_380_004_385, // China => 1_439_323_776,
Chain With
Return a stream chaining additional sources together into a single consecutive stream.
$stream->chainWith(iterable ...$iterables): Stream
use IterTools\Stream; $input = [1, 2, 3]; $result = Stream::of($input) ->chainWith([4, 5, 6]) ->chainWith([7, 8, 9]) ->toArray(); // 1, 2, 3, 4, 5, 6, 7, 8, 9
Compress
Compress to a new stream by filtering out data that is not selected.
$stream->compress(iterable $selectors): Stream
Selectors indicate which data. True value selects item. False value filters out data.
use IterTools\Stream; $input = [1, 2, 3]; $result = Stream::of($input) ->compress([0, 1, 1]) ->toArray(); // 2, 3
Compress Associative
Compress to a new stream by filtering out keys that are not selected.
$stream->compressAssociative(array $keys): Stream
- Standard PHP array/iterator keys only (string, integer).
use IterTools\Stream; $starWarsEpisodes = [ 'I' => 'The Phantom Menace', 'II' => 'Attack of the Clones', 'III' => 'Revenge of the Sith', 'IV' => 'A New Hope', 'V' => 'The Empire Strikes Back', 'VI' => 'Return of the Jedi', 'VII' => 'The Force Awakens', 'VIII' => 'The Last Jedi', 'IX' => 'The Rise of Skywalker', ]; $sequelTrilogyNumbers = ['VII', 'VIII', 'IX']; $sequelTrilogy = Stream::of($starWarsEpisodes) ->compressAssociative($sequelTrilogyNumbers) ->toAssociativeArray(); // 'VII' => 'The Force Awakens', // 'VIII' => 'The Last Jedi', // 'IX' => 'The Rise of Skywalker',
Chunkwise
Return a stream consisting of chunks of elements from the stream.
$stream->chunkwise(int $chunkSize): Stream
Chunk size must be at least 1.
use IterTools\Stream; $friends = ['Ross', 'Rachel', 'Chandler', 'Monica', 'Joey']; $result = Stream::of($friends) ->chunkwise(2) ->toArray(); // ['Ross', 'Rachel'], ['Chandler', 'Monica'], ['Joey']
Chunkwise Overlap
Return a stream consisting of overlapping chunks of elements from the stream.
$stream->chunkwiseOverlap(int $chunkSize, int $overlapSize, bool $includeIncompleteTail = true): Stream
- Chunk size must be at least 1.
- Overlap size must be less than chunk size.
use IterTools\Stream; $numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; $result = Stream::of($friends) ->chunkwiseOverlap(3, 1) ->toArray() // [1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]
Distinct
Return a stream filtering out elements from the stream only returning distinct elements.
$stream->distinct(bool $strict = true): Stream
Defaults to strict type comparisons. Set strict to false for type coercion comparisons.
use IterTools\Stream; $input = [1, 2, 1, 2, 3, 3, '1', '1', '2', '3']; $stream = Stream::of($input) ->distinct() ->toArray(); // 1, 2, 3, '1', '2', '3' $stream = Stream::of($input) ->distinct(false) ->toArray(); // 1, 2, 3
Distinct By
Return a stream filtering out elements from the stream only returning distinct elements according to a custom comparator function.
$stream->distinctBy(callable $compareBy): Stream
use IterTools\Stream; $streetFighterConsoleReleases = [ ['id' => '112233', 'name' => 'Street Fighter 3 3rd Strike', 'console' => 'Dreamcast'], ['id' => '223344', 'name' => 'Street Fighter 3 3rd Strike', 'console' => 'PS4'], ['id' => '334455', 'name' => 'Street Fighter 3 3rd Strike', 'console' => 'PS5'], ['id' => '445566', 'name' => 'Street Fighter VI', 'console' => 'PS4'], ['id' => '556677', 'name' => 'Street Fighter VI', 'console' => 'PS5'], ['id' => '667799', 'name' => 'Street Fighter VI', 'console' => 'PC'], ]; $stream = Stream::of($streetFighterConsoleReleases) ->distinctBy(fn ($sfTitle) => $sfTitle['name']) ->toArray(); // Contains one SF3 3rd Strike entry and one SFVI entry
Drop While
Drop elements from the stream while the predicate function is true.
$stream->dropWhile(callable $predicate): Stream
Once the predicate function returns false once, all remaining elements are returned.
use IterTools\Stream; $input = [1, 2, 3, 4, 5] $result = Stream::of($input) ->dropWhile(fn ($value) => $value < 3) ->toArray(); // 3, 4, 5
Filter
Filter out elements from the stream only keeping elements where there predicate function is true.
$stream->filter(callable $predicate): Stream
use IterTools\Stream; $input = [1, -1, 2, -2, 3, -3]; $result = Stream::of($input) ->filter(fn ($value) => $value > 0) ->toArray(); // 1, 2, 3
Filter True
Filter out elements from the stream only keeping elements that are truthy.
$stream->filterTrue(): Stream
use IterTools\Stream; $input = [0, 1, 2, 3, 0, 4]; $result = Stream::of($input) ->filterTrue() ->toArray(); // 1, 2, 3, 4
Filter False
Filter out elements from the stream only keeping elements that are falsy.
$stream->filterFalse(): Stream
use IterTools\Stream; $input = [0, 1, 2, 3, 0, 4]; $result = Stream::of($input) ->filterFalse() ->toArray(); // 0, 0
Filter Keys
Filter out elements from stream only keeping elements where the predicate function on the keys are true.
$stream->filterKeys(callable $filter): Stream
$olympics = [ 2000 => 'Sydney', 2002 => 'Salt Lake City', 2004 => 'Athens', 2006 => 'Turin', 2008 => 'Beijing', 2010 => 'Vancouver', 2012 => 'London', 2014 => 'Sochi', 2016 => 'Rio de Janeiro', 2018 => 'Pyeongchang', 2020 => 'Tokyo', 2022 => 'Beijing', ]; $winterFilter = fn ($year) => $year % 4 === 2; $result = Stream::of($olympics) ->filterKeys($winterFilter) ->toAssociativeArray(); } // 2002 => Salt Lake City // 2006 => Turin // 2010 => Vancouver // 2014 => Sochi // 2018 => Pyeongchang // 2022 => Beijing
Flat Map
Map a function onto the elements of the stream and flatten the results.
$stream->flatMap(callable $mapper): Stream
$data = [1, 2, 3, 4, 5]; $mapper fn ($item) => ($item % 2 === 0) ? [$item, $item] : $item; $result = Stream::of($data) ->flatMap($mapper) ->toArray(); // [1, 2, 2, 3, 4, 4, 5]
Flatten
Flatten a multidimensional stream.
$stream->flatten(int $dimensions = 1): Stream
$data = [1, [2, 3], [4, 5]]; $result = Stream::of($data) ->flatten($mapper) ->toArray(); // [1, 2, 3, 4, 5]
Frequencies
Frequency distribution of the stream elements.
$stream->frequencies(bool $strict = true): Stream
use IterTools\Stream; $grades = ['A', 'A', 'B', 'B', 'B', 'C']; $result = Stream::of($grades) ->frequencies() ->toAssociativeArray(); // ['A' => 2, 'B' => 3, 'C' => 1]
Group By
Return a stream grouping by a common data element.
$stream->groupBy(callable $groupKeyFunction, callable $itemKeyFunction = null): Stream
- The
$groupKeyFunction
determines the key to group elements by. - The optional
$itemKeyFunction
allows custom indexes within each group member.
use IterTools\Stream; $input = [1, -1, 2, -2, 3, -3]; $groups = Stream::of($input) ->groupBy(fn ($item) => $item > 0 ? 'positive' : 'negative'); foreach ($groups as $group => $item) { // 'positive' => [1, 2, 3], 'negative' => [-1, -2, -3] }
Infinite Cycle
Return a stream cycling through the elements of stream sequentially forever.
$stream->infiniteCycle(): Stream
use IterTools\Stream; $input = [1, 2, 3]; $result = Stream::of($input) ->infiniteCycle() ->print(); // 1, 2, 3, 1, 2, 3, ...
Intersection With
Return a stream intersecting the stream with the input iterables.
$stream->intersectionWith(iterable ...$iterables): Stream
use IterTools\Stream; $numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; $numerics = ['1', '2', 3, 4, 5, 6, 7, '8', '9']; $oddNumbers = [1, 3, 5, 7, 9, 11]; $stream = Stream::of($numbers) ->intersectionWith($numerics, $oddNumbers) ->toArray(); // 3, 5, 7
Intersection Coercive With
Return a stream intersecting the stream with the input iterables using type coercion.
$stream->intersectionCoerciveWith(iterable ...$iterables): Stream
use IterTools\Stream; $languages = ['php', 'python', 'c++', 'java', 'c#', 'javascript', 'typescript']; $scriptLanguages = ['php', 'python', 'javascript', 'typescript']; $supportsInterfaces = ['php', 'java', 'c#', 'typescript']; $stream = Stream::of($languages) ->intersectionCoerciveWith($scriptLanguages, $supportsInterfaces) ->toArray(); // 'php', 'typescript'
Limit
Return a stream up to a limit.
Stops even if more data available if limit reached.
$stream->limit(int $limit): Stream
Use IterTools\Single; $matrixMovies = ['The Matrix', 'The Matrix Reloaded', 'The Matrix Revolutions', 'The Matrix Resurrections']; $limit = 1; $goodMovies = Stream::of($matrixMovies) ->limit($limit) ->toArray(); // 'The Matrix' (and nothing else)
Map
Return a stream containing the result of mapping a function onto each element of the stream.
$stream->map(callable $function): Stream
use IterTools\Stream; $grades = [100, 95, 98, 89, 100]; $result = Stream::of($grades) ->map(fn ($grade) => $grade === 100 ? 'A' : 'F') ->toArray(); // A, F, F, F, A
Pairwise
Return a stream consisting of pairs of elements from the stream.
$stream->pairwise(): Stream
Returns empty stream if given collection contains less than 2 elements.
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $stream = Stream::of($input) ->pairwise() ->toArray(); // [1, 2], [2, 3], [3, 4], [4, 5]
Partial Intersection With
Return a stream partially intersecting the stream with the input iterables.
$stream->partialIntersectionWith(int $minIntersectionCount, iterable ...$iterables): Stream
use IterTools\Stream; $numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; $numerics = ['1', '2', 3, 4, 5, 6, 7, '8', '9']; $oddNumbers = [1, 3, 5, 7, 9, 11]; $stream = Stream::of($numbers) ->partialIntersectionWith($numerics, $oddNumbers) ->toArray(); // 1, 3, 4, 5, 6, 7, 9
Partial Intersection Coercive With
Return a stream partially intersecting the stream with the input iterables using type coercion.
$stream->partialIntersectionCoerciveWith(int $minIntersectionCount, iterable ...$iterables): Stream
use IterTools\Stream; $languages = ['php', 'python', 'c++', 'java', 'c#', 'javascript', 'typescript']; $scriptLanguages = ['php', 'python', 'javascript', 'typescript']; $supportsInterfaces = ['php', 'java', 'c#', 'typescript']; $stream = Stream::of($languages) ->partialIntersectionCoerciveWith(2, $scriptLanguages, $supportsInterfaces) ->toArray(); // 'php', 'python', 'java', 'typescript', 'c#', 'javascript'
Reindex
Return a new stream of key-value elements reindexed by the key indexer function.
$stream->reindex(callable $indexer): Stream
use IterTools\Stream; $data = [ [ 'title' => 'Star Wars: Episode IV – A New Hope', 'episode' => 'IV', 'year' => 1977, ], [ 'title' => 'Star Wars: Episode V – The Empire Strikes Back', 'episode' => 'V', 'year' => 1980, ], [ 'title' => 'Star Wars: Episode VI – Return of the Jedi', 'episode' => 'VI', 'year' => 1983, ], ]; $reindexFunc = fn (array $swFilm) => $swFilm['episode']; $reindexResult = Stream::of($data) ->reindex($reindexFunc) ->toAssociativeArray(); // [ // 'IV' => [ // 'title' => 'Star Wars: Episode IV – A New Hope', // 'episode' => 'IV', // 'year' => 1977, // ], // 'V' => [ // 'title' => 'Star Wars: Episode V – The Empire Strikes Back', // 'episode' => 'V', // 'year' => 1980, // ], // 'VI' => [ // 'title' => 'Star Wars: Episode VI – Return of the Jedi', // 'episode' => 'VI', // 'year' => 1983, // ], // ]
Relative Frequencies
Relative frequency distribution of the stream elements.
$stream->relativeFrequencies(bool $strict = true): Stream
use IterTools\Stream; $grades = ['A', 'A', 'B', 'B', 'B', 'C']; $result = Stream::of($grades) ->relativeFrequencies() ->toAssociativeArray(); // A => 0.33, B => 0.5, C => 0.166
Reverse
Reverse the elements of a stream.
$stream->reverse(): Stream
use IterTools\Stream; $words = ['are', 'you', 'as' ,'bored', 'as', 'I', 'am']; $reversed = Stream::of($words) ->reverse() ->toString(' '); // am I as bored as you are
Running Average
Return a stream accumulating the running average (mean) over the stream.
$stream->runningAverage(int|float|null $initialValue = null): Stream
use IterTools\Stream; $input = [1, 3, 5]; $result = Stream::of($input) ->runningAverage() ->toArray(); // 1, 2, 3
Running Difference
Return a stream accumulating the running difference over the stream.
$stream->runningDifference(int|float|null $initialValue = null): Stream
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($input) ->runningDifference() ->toArray(); // -1, -3, -6, -10, -15
Running Max
Return a stream accumulating the running max over the stream.
$stream->runningMax(int|float|null $initialValue = null): Stream
use IterTools\Stream; $input = [1, -1, 2, -2, 3, -3]; $result = Stream::of($input) ->runningMax() ->toArray(); // 1, 1, 2, 2, 3, 3
Running Min
Return a stream accumulating the running min over the stream.
$stream->runningMin(int|float|null $initialValue = null): Stream
use IterTools\Stream; $input = [1, -1, 2, -2, 3, -3]; $result = Stream::of($input) ->runningMin() ->toArray(); // 1, -1, -1, -2, -2, -3
Running Product
Return a stream accumulating the running product over the stream.
$stream->runningProduct(int|float|null $initialValue = null): Stream
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($input) ->runningProduct() ->toArray(); // 1, 2, 6, 24, 120
Running Total
Return a stream accumulating the running total over the stream.
$stream->runningTotal(int|float|null $initialValue = null): Stream
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($input) ->runningTotal() ->toArray(); // 1, 3, 6, 10, 15
Skip
Skip some elements of the stream.
$stream->skip(int $count, int $offset = 0): Stream
use IterTools\Stream; $movies = [ 'The Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith', 'A New Hope', 'The Empire Strikes Back', 'Return of the Jedi', 'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker' ]; $onlyTheBest = Stream::of($movies) ->skip(3) ->skip(3, 3) ->toArray(); // 'A New Hope', 'The Empire Strikes Back', 'Return of the Jedi'
Slice
Extract a slice of the stream.
$stream->slice(int $start = 0, int $count = null, int $step = 1)
use IterTools\Stream; $olympics = [1992, 1994, 1996, 1998, 2000, 2002, 2004, 2006, 2008, 2010, 2012, 2014, 2016, 2018, 2020, 2022]; $summerOlympics = Stream::of($olympics) ->slice(0, 8, 2) ->toArray(); // [1992, 1996, 2000, 2004, 2008, 2012, 2016, 2020]
Sort
Sorts the stream.
$stream->sort(callable $comparator = null)
If comparator is not provided, the elements of the iterable source must be comparable.
use IterTools\Stream; $input = [3, 4, 5, 9, 8, 7, 1, 6, 2]; $result = Stream::of($input) ->sort() ->toArray(); // 1, 2, 3, 4, 5, 6, 7, 8, 9
Symmetric difference With
Return a stream of the symmetric difference of the stream and the given iterables.
$stream->symmetricDifferenceWith(iterable ...$iterables): Stream
Note: If input iterables produce duplicate items, then multiset intersection rules apply.
use IterTools\Stream; $a = [1, 2, 3, 4, 7]; $b = ['1', 2, 3, 5, 8]; $c = [1, 2, 3, 6, 9]; $stream = Stream::of($a) ->symmetricDifferenceWith($b, $c) ->toArray(); // '1', 4, 5, 6, 7, 8, 9
Symmetric difference Coercive With
Return a stream of the symmetric difference of the stream and the given iterables using type coercion.
$stream->symmetricDifferenceCoerciveWith(iterable ...$iterables): Stream
Note: If input iterables produce duplicate items, then multiset intersection rules apply.
use IterTools\Stream; $a = [1, 2, 3, 4, 7]; $b = ['1', 2, 3, 5, 8]; $c = [1, 2, 3, 6, 9]; $stream = Stream::of($a) ->symmetricDifferenceCoerciveWith($b, $c) ->toArray(); // 4, 5, 6, 7, 8, 9
Take While
Keep elements from the stream as long as the predicate is true.
$stream->takeWhile(callable $predicate): Stream
If no predicate is provided, the boolean value of the data is used.
use IterTools\Stream; $input = [1, -1, 2, -2, 3, -3]; $result = Stream::of($input) ->takeWhile(fn ($value) => abs($value) < 3) ->toArray(); // 1, -1, 2, -2
Union With
Return a stream consisting of the union of the stream and the input iterables.
$stream->unionWith(iterable ...$iterables): Stream
Note: If input iterables produce duplicate items, then multiset union rules apply.
use IterTools\Stream; $input = [1, 2, 3]; $stream = Stream::of($input) ->unionWith([3, 4, 5, 6]) ->toArray(); // [1, 2, 3, 4, 5, 6]
Union Coercive With
Return a stream consisting of the union of the stream and the input iterables using type coercion.
$stream->unionCoerciveWith(iterable ...$iterables): Stream
Note: If input iterables produce duplicate items, then multiset union rules apply.
use IterTools\Stream; $input = [1, 2, 3]; $stream = Stream::of($input) ->unionCoerciveWith(['3', 4, 5, 6]) ->toArray(); // [1, 2, 3, 4, 5, 6]
Zip With
Return a stream consisting of multiple iterable collections streamed simultaneously.
$stream->zipWith(iterable ...$iterables): Stream
For uneven lengths, iterations stops when the shortest iterable is exhausted.
use IterTools\Stream; $input = [1, 2, 3]; $stream = Stream::of($input) ->zipWith([4, 5, 6]) ->zipWith([7, 8, 9]) ->toArray(); // [1, 4, 7], [2, 5, 8], [3, 6, 9]
Zip Filled With
Return a stream consisting of multiple iterable collections, using a default filler value if lengths no equal.
$stream->zipFilledWith(mixed $default, iterable ...$iterables): Stream
use IterTools\Stream; $input = [1, 2, 3]; $stream = Stream::of($input) ->zipFilledWith('?', ['A', 'B']); foreach ($stream as $zipped) { // [1, A], [2, B], [3, ?] }
Zip Equal With
Return a stream consisting of multiple iterable collections of equal lengths streamed simultaneously.
$stream->zipEqualWith(iterable ...$iterables): Stream
Works like Stream::zipWith()
method but throws \LengthException if lengths not equal,
i.e., at least one iterator ends before the others.
use IterTools\Stream; $input = [1, 2, 3]; $stream = Stream::of($input) ->zipEqualWith([4, 5, 6]) ->zipEqualWith([7, 8, 9]); foreach ($stream as $zipped) { // [1, 4, 7], [2, 5, 8], [3, 6, 9] }
Zip Longest With
Return a stream consisting of multiple iterable collections streamed simultaneously.
$stream->zipLongestWith(iterable ...$iterables): Stream
- Iteration continues until the longest iterable is exhausted.
- For uneven lengths, the exhausted iterables will produce null for the remaining iterations.
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $stream = Stream::of($input) ->zipLongestWith([4, 5, 6]) ->zipLongestWith([7, 8, 9, 10]); foreach ($stream as $zipped) { // [1, 4, 7], [2, 5, 8], [3, 6, 9], [4, null, 10], [null, null, 5] }
Stream Terminal Operations
Stream Summary Terminal Operations
All Match
Returns true if all elements match the predicate function.
$stream->allMatch(callable $predicate): bool
use IterTools\Summary; $finalFantasyNumbers = [4, 5, 6]; $isOnSuperNintendo = fn ($ff) => $ff >= 4 && $ff <= 6; $boolean = Stream::of($finalFantasyNumbers) ->allMatch($isOnSuperNintendo); // true
All Unique
Returns true if all elements are unique.
$stream->allUnique(bool $strict = true): bool
Defaults to strict type comparisons. Set strict to false for type coercion comparisons.
use IterTools\Summary; $items = ['fingerprints', 'snowflakes', 'eyes', 'DNA'] $boolean = Stream::of($items) ->allUnique(); // true
Any Match
Returns true if any element matches the predicate function.
$stream->anyMatch(callable $predicate): bool
use IterTools\Summary; $answers = ['fish', 'towel', 42, "don't panic"]; $isUltimateAnswer = fn ($a) => a == 42; $boolean = Stream::of($answers) ->anyMatch($answers, $isUltimateAnswer); // true
Are Permutations With
Returns true if all iterables are permutations with stream.
$stream->arePermutationsWith(...$iterables): bool
use IterTools\Summary; $rite = ['r', 'i', 't', 'e']; $reit = ['r', 'e', 'i', 't']; $tier = ['t', 'i', 'e', 'r']; $tire = ['t', 'i', 'r', 'e']; $trie = ['t', 'r', 'i', 'e']; $boolean = Stream::of(['i', 't', 'e', 'r']) ->arePermutationsWith($rite, $reit, $tier, $tire, $trie); // true
Are Permutations Coercive With
Returns true if all iterables are permutations with stream with type coercion.
$stream->arePermutationsCoerciveWith(...$iterables): bool
use IterTools\Summary; $set2 = [2.0, '1', 3]; $set3 = [3, 2, 1]; $boolean = Stream::of([1, 2.0, '3']) ->arePermutationsCoerciveWith($set2, $set3); // true
Exactly N
Returns true if exactly n items are true according to a predicate function.
- Predicate is optional.
- Default predicate is boolean value of each item.
$stream->exactlyN(int $n, callable $predicate = null): bool
use IterTools\Summary; $twoTruthsAndALie = [true, true, false]; $n = 2; $boolean = Stream::of($twoTruthsAndALie)->exactlyN($n); // true
Is Empty
Returns true if the stream is empty having no items.
$stream->isEmpty(): bool
use IterTools\Summary; $numbers = [0, 1, 2, 3, 4, 5]; $filterFunc = fn ($x) => $x > 10; $boolean = Stream::($numbers) ->filter($filterFunc) ->isEmpty(); // true
Is Partitioned
Returns true if all elements of given collection that satisfy the predicate appear before all elements that don't.
- Returns true for empty collection or for collection with single item.
- Default predicate if not provided is the boolean value of each data item.
$stream->isPartitioned(callable $predicate = null): bool
use IterTools\Summary; $numbers = [0, 2, 4, 1, 3, 5]; $evensBeforeOdds = fn ($item) => $item % 2 === 0; $boolean = Stream::($numbers) ->isPartitioned($evensBeforeOdds); // true
Is Sorted
Returns true if iterable source is sorted in ascending order; otherwise false.
$stream->isSorted(): bool
Items of iterable source must be comparable.
Returns true if iterable source is empty or has only one element.
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($input) ->isSorted(); // true $input = [1, 2, 3, 2, 1]; $result = Stream::of($input) ->isSorted(); // false
Is Reversed
Returns true if iterable source is sorted in reverse descending order; otherwise false.
$stream->isReversed(): bool
Items of iterable source must be comparable.
Returns true if iterable source is empty or has only one element.
use IterTools\Stream; $input = [5, 4, 3, 2, 1]; $result = Stream::of($input) ->isReversed(); // true $input = [1, 2, 3, 2, 1]; $result = Stream::of($input) ->isReversed(); // false
None Match
Returns true if no element matches the predicate function.
$stream->noneMatch(callable $predicate): bool
use IterTools\Summary; $grades = [45, 50, 61, 0]; $isPassingGrade = fn ($grade) => $grade >= 70; $boolean = Stream::of($grades)->noneMatch($isPassingGrade); // true
Same With
Returns true if iterable source and all given collections are the same.
$stream->sameWith(iterable ...$iterables): bool
For empty iterables list returns true.
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($input) ->sameWith([1, 2, 3, 4, 5]); // true $result = Stream::of($input) ->sameWith([5, 4, 3, 2, 1]); // false
Same Count With
Returns true if iterable source and all given collections have the same lengths.
$stream->sameCountWith(iterable ...$iterables): bool
For empty iterables list returns true.
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($input) ->sameCountWith([5, 4, 3, 2, 1]); // true $result = Stream::of($input) ->sameCountWith([1, 2, 3]); // false
Stream Reduction Terminal Operations
To Average
Reduces iterable source to the mean average of its items.
$stream->toAverage(): mixed
Returns null if iterable source is empty.
use IterTools\Stream; $input = [2, 4, 6, 8]; $result = Stream::of($iterable) ->toAverage(); // 5
To Count
Reduces iterable source to its length.
$stream->toCount(): mixed
use IterTools\Stream; $input = [10, 20, 30, 40, 50]; $result = Stream::of($iterable) ->toCount(); // 5
To First
Reduces iterable source to its first element.
$stream->toFirst(): mixed
Throws \LengthException
if iterable source is empty.
use IterTools\Stream; $input = [10, 20, 30]; $result = Stream::of($input) ->toFirst(); // 10
To First And Last
Reduces iterable source to its first and last elements.
$stream->toFirstAndLast(): array{mixed, mixed}
Throws \LengthException
if iterable source is empty.
use IterTools\Stream; $input = [10, 20, 30]; $result = Stream::of($input) ->toFirstAndLast(); // [10, 30]
To Last
Reduces iterable source to its last element.
$stream->toLast(): mixed
Throws \LengthException
if iterable source is empty.
use IterTools\Stream; $input = [10, 20, 30]; $result = Stream::of($input) ->toLast(); // 30
To Max
Reduces iterable source to its max value.
$stream->toMax(callable $compareBy = null): mixed
- Optional callable param
$compareBy
must return comparable value. - If
$compareBy
is not provided then items of given collection must be comparable. - Returns null if collection is empty.
use IterTools\Stream; $input = [1, -1, 2, -2, 3, -3]; $result = Stream::of($iterable) ->toMax(); // 3
To Min
Reduces iterable source to its min value.
$stream->toMin(callable $compareBy = null): mixed
- Optional callable param
$compareBy
must return comparable value. - If
$compareBy
is not provided then items of given collection must be comparable. - Returns null if collection is empty.
use IterTools\Stream; $input = [1, -1, 2, -2, 3, -3]; $result = Stream::of($iterable) ->toMin(); // -3
To Min Max
Reduces stream to array of its upper and lower bounds (max and min).
$stream->toMinMax(callable $compareBy = null): array
- Optional callable param
$compareBy
must return comparable value. - If
$compareBy
is not provided then items of given collection must be comparable. - Returns
[null, null]
if given collection is empty.
use IterTools\Stream; $numbers = [1, 2, 7, -1, -2, -3]; [$min, $max] = Stream::of($numbers) ->toMinMax(); // [-3, 7]
To Nth
Reduces stream to value at the nth position.
$stream->toNth(int $position): mixed
Returns null if iterable source is empty.
use IterTools\Stream; $lotrMovies = ['The Fellowship of the Ring', 'The Two Towers', 'The Return of the King']; $result = Stream::of($lotrMovies) ->toNth(2); // The Return of the King
To Product
Reduces stream to the product of its items.
$stream->toProduct(): mixed
Returns null if iterable source is empty.
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($iterable) ->toProduct(); // 120
To Random Value
Reduces stream to a random value within it.
$stream->toRandomValue(): mixed
use IterTools\Stream; $rpsHands = ['rock', 'paper', 'scissors'] $range = Stream::of($numbers) ->map('strtoupper') ->toRandomValue(); // e.g., rock
To Range
Reduces stream to its range (difference between max and min).
$stream->toRange(): int|float
Returns 0
if iterable source is empty.
use IterTools\Stream; $grades = [100, 90, 80, 85, 95]; $range = Stream::of($numbers) ->toRange(); // 20
To String
Reduces to a string joining all elements.
- Optional separator to insert between items.
- Optional prefix to prepend to the string.
- Optional suffix to append to the string.
$stream->toString(string $separator = '', string $prefix = '', string $suffix = ''): string
use IterTools\Stream; $words = ['IterTools', 'PHP', 'v1.0']; $string = Stream::of($words)->toString($words); // IterToolsPHPv1.0 $string = Stream::of($words)->toString($words, '-'); // IterTools-PHP-v1.0 $string = Stream::of($words)->toString($words, '-', 'Library: '); // Library: IterTools-PHP-v1.0 $string = Stream::of($words)->toString($words, '-', 'Library: ', '!'); // Library: IterTools-PHP-v1.0!
To Sum
Reduces iterable source to the sum of its items.
$stream->toSum(): mixed
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($iterable) ->toSum(); // 15
To Value
Reduces iterable source like array_reduce() function.
But unlike array_reduce()
, it works with all iterable
types.
$stream->toValue(callable $reducer, mixed $initialValue): mixed
use IterTools\Stream; $input = [1, 2, 3, 4, 5]; $result = Stream::of($iterable) ->toValue(fn ($carry, $item) => $carry + $item); // 15
Transformation Terminal Operations
To Array
Returns an array of stream elements.
$stream->toArray(): array
use IterTools\Stream; $array = Stream::of([1, 1, 2, 2, 3, 4, 5]) ->distinct() ->map(fn ($x) => $x**2) ->toArray(); // [1, 4, 9, 16, 25]
To Associative Array
Returns a key-value map of stream elements.
$stream->toAssociativeArray(callable $keyFunc, callable $valueFunc): array
use IterTools\Stream; $keyFunc $array = Stream::of(['message 1', 'message 2', 'message 3']) ->map('strtoupper') ->toAssociativeArray( fn ($s) => \md5($s), fn ($s) => $s ); // [3b3f2272b3b904d342b2d0df2bf31ed4 => MESSAGE 1, 43638d919cfb8ea31979880f1a2bb146 => MESSAGE 2, ... ]
Tee
Return several independent (duplicated) streams.
$stream->tee(int $count): array
use IterTools\Transform; $daysOfWeek = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun']; $count = 3; [$week1Stream, $week2Stream, $week3Stream] = Stream::of($daysOfWeek) ->tee($count); // Each $weekStream contains ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun']
Side Effect Terminal Operations
Call For Each
Perform an action via a callable on each item in the stream.
$stream->callForEach(callable $function): void
use IterTools\Stream; $languages = ['PHP', 'Python', 'Java', 'Go']; $mascots = ['elephant', 'snake', 'bean', 'gopher']; $zipPrinter = fn ($zipped) => print("{$zipped[0]}'s mascot: {$zipped[1]}"); Stream::of($languages) ->zipWith($mascots) ->callForEach($zipPrinter); // PHP's mascot: elephant // Python's mascot: snake // ...
Prints each item in the stream.
- Items must be printable.
$stream->print(string $separator = '', string $prefix = '', string $suffix = ''): void
use IterTools\Stream; $words = ['IterTools', 'PHP', 'v1.0']; Stream::of($words)->print(); // IterToolsPHPv1.0 Stream::of($words)->print('-'); // IterTools-PHP-v1.0 Stream::of($words)->print('-', 'Library: '); // Library: IterTools-PHP-v1.0 Stream::of($words)->print('-', 'Library: ', '!'); // Library: IterTools-PHP-v1.0!
Print Line
Prints each item in the stream on its own line.
- Items must be printable.
$stream->println(): void
use IterTools\Stream; $words = ['IterTools', 'PHP', 'v1.0']; Stream::of($words)->printLn(); // IterTools // PHP // v1.0
To CSV File
Write the contents of the stream to a CSV file.
$stream->toCsvFile(resource $fileHandle, array $header = null, string 'separator = ',', string $enclosure = '"', string $escape = '\\'): void
use IterTools\Stream; $starWarsMovies = [ ['Star Wars: Episode IV – A New Hope', 'IV', 1977], ['Star Wars: Episode V – The Empire Strikes Back', 'V', 1980], ['Star Wars: Episode VI – Return of the Jedi', 'VI', 1983], ]; $header = ['title', 'episode', 'year']; Stream::of($data) ->toCsvFile($fh, $header); // title,episode,year // "Star Wars: Episode IV – A New Hope",IV,1977 // "Star Wars: Episode V – The Empire Strikes Back",V,1980 // "Star Wars: Episode VI – Return of the Jedi",VI,1983
To File
Write the contents of the stream to a file.
$stream->toFile(resource $fileHandle, string $newLineSeparator = \PHP_EOL, string $header = null, string $footer = null): void
use IterTools\Stream; $data = ['item1', 'item2', 'item3']; $header = '<ul>'; $footer = '</ul>'; Stream::of($data) ->map(fn ($item) => " <li>$item</li>") ->toFile($fh, \PHP_EOL, $header, $footer); // <ul> // <li>item1</li> // <li>item2</li> // <li>item3</li> // </ul>
Stream Debug Operations
Peek
Peek at each element between other Stream operations to do some action without modifying the stream.
$stream->peek(callable $callback): Stream
use IterTools\Stream; $logger = new SimpleLog\Logger('/tmp/log.txt', 'iterTools'); Stream::of(['some', 'items']) ->map('strtoupper') ->peek(fn ($x) => $logger->info($x)) ->foreach($someComplexCallable);
Peek Stream
Peek at the entire stream between other Stream operations to do some action without modifying the stream.
$stream->peekStream(callable $callback): Stream
use IterTools\Stream; $logger = new SimpleLog\Logger('/tmp/log.txt', 'iterTools'); Stream::of(['some', 'items']) ->map('strtoupper') ->peekStream(fn ($stream) => $logger->info($stream)) ->foreach($someComplexCallable);
Peek Print
Peek at each element between other Stream operations to print each item without modifying the stream.
$stream->peekPrint(string $separator = '', string $prefix = '', string $suffix = ''): void
use IterTools\Stream; Stream::of(['some', 'items']) ->map('strtoupper') ->peekPrint() ->foreach($someComplexCallable);
Peek PrintR
Peek at each element between other Stream operations to print_r
each item without modifying the stream.
$stream->peekPrintR(callable $callback): void
use IterTools\Stream; Stream::of(['some', 'items']) ->map('strtoupper') ->peekPrintR() ->foreach($someComplexCallable);
Print R
print_r
each item in the stream.
$stream->printR(): void
use IterTools\Stream; $items = [$string, $array, $object]; Stream::of($words)->printR(); // print_r output
Var Dump
var_dump
each item in the stream.
$stream->varDump(): void
use IterTools\Stream; $items = [$string, $array, $object]; Stream::of($words)->varDump(); // var_dump output
Composition
IterTools can be combined to create new iterable compositions.
Zip Strings
use IterTools\Multi; use IterTools\Single; $letters = 'ABCDEFGHI'; $numbers = '123456789'; foreach (Multi::zip(Single::string($letters), Single::string($numbers)) as [$letter, $number]) { $battleshipMove = new BattleshipMove($letter, $number) } // A1, B2, C3
Chain Strings
use IterTools\Multi; use IterTools\Single; $letters = 'abc'; $numbers = '123'; foreach (Multi::chain(Single::string($letters), Single::string($numbers)) as $character) { print($character); } // a, b, c, 1, 2, 3
Strict and Coercive Types
When there is an option, the default will do strict type comparisons:
- scalars: compares strictly by type
- objects: always treats different instances as not equal to each other
- arrays: compares serialized
When type coercion (non-strict types) is available and enabled via optional flag:
- scalars: compares by value via type juggling
- objects: compares serialized
- arrays: compares serialized
Standards
IterTools PHP conforms to the following standards:
- PSR-1 - Basic coding standard (http://www.php-fig.org/psr/psr-1/)
- PSR-4 - Autoloader (http://www.php-fig.org/psr/psr-4/)
- PSR-12 - Extended coding style guide (http://www.php-fig.org/psr/psr-12/)
License
IterTools PHP is licensed under the MIT License.
Similar Libraries in Other Languages
IterTools functionality is not limited to PHP and Python. Other languages have similar libraries. Familiar functionality is available when working in other languages.
- IterTools TypeScript/Javascript
- IterTools Python: The original!