gielfeldt / iterators
Various iterators.
Installs: 8 010
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 3
Forks: 0
Open Issues: 0
Requires
- php: >=7.0.0
Requires (Dev)
- mikey179/vfsstream: ^1.6
- phpunit/phpunit: ^6
This package is not auto-updated.
Last update: 2024-12-12 13:33:04 UTC
README
Installation
composer require gielfeldt/iterators
Iterators
This library contains a bunch of various iterators that I made primarily for getting more acquainted with iterators in PHP. Some may be useful. Some may be silly.
Enjoy!
CachingIterator
Cache an iterator for multiple iterations.
use Gielfeldt\Iterators\CachingIterator; $input = new \ArrayIterator(range(1, 4)); $input = new \NoRewindIterator($input); $cached = new CachingIterator($input); print_r(iterator_to_array($cached)); print_r(iterator_to_array($cached));
Output:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
ChecksumIterator
Generate a checksum for an iterator, either per iteration or the entire dataset.
use Gielfeldt\Iterators\ChecksumIterator; $input = new \ArrayIterator([ ['key1' => 'value1'], ['key2' => 'value2'], ['key3' => 'value3'], ]); $iterator = new ChecksumIterator($input, 'md5'); foreach ($iterator as $key => $value) { print "$key => $value\n"; } var_dump($iterator->getChecksum()); var_dump((string) $iterator);
Output:
0 => e2e517365ffe6fedd279364e3fa74786
1 => f0a0db0fc9abe193b21fd657fe678884
2 => c04f606bb5bba82282dfa93edb59c6ee
string(32) "4fd19adc845da6fdd9c7c394f4626bac"
string(32) "4fd19adc845da6fdd9c7c394f4626bac"
ChunkIterator
Split an iterator into chunks of iterators.
use Gielfeldt\Iterators\ChunkIterator; use Gielfeldt\Iterators\AtomicTempFileObject; // Split a file into multiple files of a 100 lines each. $file = new \SplFileObject('inputfile'); foreach (new ChunkIterator($file, 100) as $i => $lines) { AtomicTempFileObject::file_put_contents("outputfile.part.$i", implode("", iterator_to_array($lines))); }
CloningIterator
Clone each value in iteration.
use Gielfeldt\Iterators\CloningIterator; $object1 = (object) ['value' => 'test1']; $object2 = (object) ['value' => 'test2']; $object3 = (object) ['value' => 'test3']; $input = new \ArrayIterator([$object1, $object2, $object3]); $iterator = new CloningIterator($input); $cloned = iterator_to_array($iterator); $object1->value = 'MODIFIED'; var_dump(iterator_to_array($input)); var_dump($cloned);
Output:
array(3) {
[0] =>
class stdClass#2 (1) {
public $value =>
string(8) "MODIFIED"
}
[1] =>
class stdClass#3 (1) {
public $value =>
string(5) "test2"
}
[2] =>
class stdClass#4 (1) {
public $value =>
string(5) "test3"
}
}
array(3) {
[0] =>
class stdClass#9 (1) {
public $value =>
string(5) "test1"
}
[1] =>
class stdClass#10 (1) {
public $value =>
string(5) "test2"
}
[2] =>
class stdClass#11 (1) {
public $value =>
string(5) "test3"
}
}
CombineIterator
Similar to array_combine(). However, iterators can have non-unique keys. Be aware of this when using iterator_to_array();
use Gielfeldt\Iterators\CombineIterator; $keys = new \ArrayIterator(['key1', 'key2', 'key3', 'key1', 'key2', 'key3']); $values = new \ArrayIterator(['value1', 'value2', 'value3', 'value4', 'value5', 'value6']); $iterator = new CombineIterator($keys, $values); foreach ($iterator as $key => $value) { print "$key => $value\n"; } print_r(iterator_to_array($iterator));
Output:
key1 => value1
key2 => value2
key3 => value3
key1 => value4
key2 => value5
key3 => value6
Array
(
[key1] => value4
[key2] => value5
[key3] => value6
)
CountableIterator
Takes any iterator and makes it countable, simply by iterating through it and counting.
use Gielfeldt\Iterators\CountableIterator; $some_noncountable_iterator = new \IteratorIterator(new \ArrayIterator([1, 2, 3])); $iterator = new CountableIterator($some_noncountable_iterator); var_dump(count($iterator));
Output:
int(3)
DiffIterator
Compares two iterators. Similar to array_diff(). Possible to set a custom compare function.
use Gielfeldt\Iterators\DiffIterator; $input1 = new \ArrayIterator(['key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3']); $input2 = new \ArrayIterator(['key11' => 'value1', 'key22' => 'value1', 'key2' => 'value3']); $input3 = new \ArrayIterator(['key1' => 'value2', 'key2' => 'value2', 'key33' => 'value3']); $iterator = new DiffIterator($input1, $input2, $input3); $iterator->setDiff(function ($iterator, $key, $value) { return $iterator->key() == $key && $iterator->current() == $value; }); print_r(iterator_to_array($iterator));
Output:
Array
(
[key1] => value1
[key3] => value3
)
FiniteIterator
Provide an end condition through an anonymous function for an iterator.
use Gielfeldt\Iterators\FiniteIterator; $input = new \ArrayIterator(range(1, 8)); $some = new FiniteIterator($input, function ($iterator) { return $iterator->current() > 5; }); print_r(iterator_to_array($some));
Output:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
FlipIterator
Similar to array_flip(). However, iterators can have non-unique keys. Be aware of this when using iterator_to_array();
use Gielfeldt\Iterators\FlipIterator; $input = new \ArrayIterator([ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', 'key4' => 'value1', 'key5' => 'value2', 'key6' => 'value3', ]); $iterator = new FlipIterator($input); foreach ($iterator as $key => $value) { print "$key => $value\n"; } print_r(iterator_to_array($iterator));
Output:
value1 => key1
value2 => key2
value3 => key3
value1 => key4
value2 => key5
value3 => key6
Array
(
[value1] => key4
[value2] => key5
[value3] => key6
)
GlobIterator
Similar to \GlobIterator, but supports **
use Gielfeldt\Iterators\GlobIterator; $iterator = new GlobIterator('/tmp/**.log'); var_dump(iterator_to_array($iterator));
Output:
array(2) {
'/tmp/one.log' =>
class Gielfeldt\Iterators\GlobIteratorFileInfo#17 (2) {
private $pathName =>
string(20) "/tmp/one.log"
private $fileName =>
string(10) "one.log"
}
'/tmp/somedir/two.log' =>
class Gielfeldt\Iterators\GlobIteratorFileInfo#16 (2) {
private $pathName =>
string(20) "/tmp/somedir/two.log"
private $fileName =>
string(15) "two.log"
}
}
IndexIterator
Iterate only through certain rows of an iterator.
use Gielfeldt\Iterators\IndexIterator; $input = new \ArrayIterator([ 'test1' => 'val6', 'test2' => 'val5', 'test3' => 'val4', 'test4' => 'val3', 'test5' => 'val2', 'test6' => 'val1', ]); $some = new IndexIterator($input, [2, 3, 5]); print_r(iterator_to_array($some));
Output:
Array
(
[test3] => val4
[test4] => val3
[test6] => val1
)
InfiniteIterator
Like SPL's InfiniteIterator but provides an additional method, getCurrentIteration().
use Gielfeldt\Iterators\InfiniteIterator; use Gielfeldt\Iterators\FiniteIterator; $input = new \ArrayIterator(range(1, 4)); $infinite = new InfiniteIterator($input); $some = new FiniteIterator($infinite, function ($iterator) { return $iterator->getCurrentIteration() >= 2 && $iterator->current() > 2; }); foreach ($some as $k => $v) { print $some->getCurrentIteration() . ": $k => $v\n"; }
Output:
0: 0 => 1
0: 1 => 2
0: 2 => 3
0: 3 => 4
1: 0 => 1
1: 1 => 2
1: 2 => 3
1: 3 => 4
2: 0 => 1
2: 1 => 2
InterleaveIterator
Interleave multiple iterators.
use Gielfeldt\Iterators\InterleaveIterator; $input1 = new \ArrayIterator([ 'key1' => 'value11', 'key2' => 'value12', 'key3' => 'value13', ]); $input2 = new \ArrayIterator([ 'key21' => 'value21', 'key22' => 'value22', 'key23' => 'value23', ]); $input3 = new \ArrayIterator([ 'key1' => 'value31', 'key2' => 'value32', 'key3' => 'value33', ]); $iterator = new InterleaveIterator($input1, $input2, $input3); foreach ($iterator as $key => $value) { print "$key => $value\n"; } print_r(iterator_to_array($iterator));
Output:
key1 => value11
key21 => value21
key1 => value31
key2 => value12
key22 => value22
key2 => value32
key3 => value13
key23 => value23
key3 => value33
Array
(
[key1] => value31
[key21] => value21
[key2] => value32
[key22] => value22
[key3] => value33
[key23] => value23
)
IntersectIterator
Similar to array_intersect(). Possible to set a custom compare function.
use Gielfeldt\Iterators\IntersectIterator; $input1 = new \ArrayIterator(['key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3']); $input2 = new \ArrayIterator(['key11' => 'value1', 'key1' => 'value1', 'key2' => 'value3']); $input3 = new \ArrayIterator(['key1' => 'value2', 'key2' => 'value2', 'key1' => 'value1']); $iterator = new IntersectIterator($input1, $input2, $input3); $iterator->setDiff(function ($iterator, $key, $value) { return $iterator->key() == $key && $iterator->current() == $value; }); print_r(iterator_to_array($iterator));
Output:
Array
(
[key1] => value1
)
TraversableIterator
Like SPL's IteratorIterator, but with a more meaningful name :-) and provides a getIndex() method.
use Gielfeldt\Iterators\TraversableIterator; $keys = range(1, 10); shuffle($keys); $values = range(1, 10); shuffle($values); $input = new \ArrayIterator(array_combine($keys, $values)); $iterator = new TraversableIterator($input); foreach ($iterator as $k => $v) { print $iterator->getIndex() . ": $k => $v\n"; }
Output:
0: 1 => 3
1: 4 => 2
2: 9 => 10
3: 3 => 8
4: 2 => 6
5: 5 => 5
6: 8 => 1
7: 10 => 9
8: 6 => 7
9: 7 => 4
KeysIterator
Similar to array_keys().
use Gielfeldt\Iterators\KeysIterator; $input = new \ArrayIterator([ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', ]); $iterator = new KeysIterator($input); print_r(iterator_to_array($iterator));
Output:
Array
(
[0] => key1
[1] => key2
[2] => key3
)
MapIterator
Similar to array_map().
use Gielfeldt\Iterators\MapIterator; $input = new \ArrayIterator([ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', 'key4' => 'value1', 'key5' => 'value2', 'key6' => 'value3', ]); // Flip keys and values. $iterator = new MapIterator($input, function ($iterator) { return [$iterator->current(), $iterator->key()]; }); foreach ($iterator as $key => $value) { print "$key => $value\n"; } print_r(iterator_to_array($iterator));
Output:
value1 => key1
value2 => key2
value3 => key3
value1 => key4
value2 => key5
value3 => key6
Array
(
[value1] => key4
[value2] => key5
[value3] => key6
)
RandomIterator
Selects a set of random elements from a traversable. Does not work with iterators that can only be traversed once. For that, see the ReservoirSamplingIterator.
use Gielfeldt\Iterators\RandomIterator; $input = new \ArrayIterator(range(1, 10)); $random = new RandomIterator($input, 4); var_dump(count($random)); print_r(iterator_to_array($random));
Output:
int(4)
Array
(
[1] => 2
[6] => 7
[7] => 8
[8] => 9
)
RepeatIterator
Repeat and iterator n times.
use Gielfeldt\Iterators\RepeatIterator; $input = new \ArrayIterator([ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', ]); $iterator = new RepeatIterator($input, 3); foreach ($iterator as $key => $value) { print "$key => $value\n"; } print_r(iterator_to_array($iterator));
Output:
key1 => value1
key2 => value2
key3 => value3
key1 => value1
key2 => value2
key3 => value3
key1 => value1
key2 => value2
key3 => value3
Array
(
[key1] => value1
[key2] => value2
[key3] => value3
)
ReplaceableIterator
Just like TraversableIterator but with a setInnerIterator() method.
use Gielfeldt\Iterators\ReplaceableIterator; $iterator = new ReplaceableIterator(new \ArrayIterator(range(1, 4))); print_r(iterator_to_array($iterator)); $iterator->setInnerIterator(new \ArrayIterator(range(5, 8))); print_r(iterator_to_array($iterator));
Output:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
Array
(
[0] => 5
[1] => 6
[2] => 7
[3] => 8
)
ReservoirSamplingIterator
Like RandomIterator but works more effeciently on iterators of unknown size or which can be traversed only once.
use Gielfeldt\Iterators\ReservoirSamplingIterator; $input = new \ArrayIterator(range(1, 10)); $input = new \NoRewindIterator($input); $random = new ReservoirSamplingIterator($input, 4); print_r(iterator_to_array($random));
Output:
int(4)
Array
(
[1] => 2
[6] => 7
[7] => 8
[8] => 9
)
ShuffleIterator
Iterate randomly over a traversable.
use Gielfeldt\Iterators\ShuffleIterator; $input = new \ArrayIterator(range(1, 10)); $shuffled = new ShuffleIterator($input); print_r(iterator_to_array($shuffled)); print_r(iterator_to_array($shuffled));
Output:
Array
(
[1] => 2
[4] => 5
[0] => 1
[9] => 10
[7] => 8
[5] => 6
[2] => 3
[8] => 9
[3] => 4
[6] => 7
)
Array
(
[1] => 2
[9] => 10
[4] => 5
[2] => 3
[5] => 6
[0] => 1
[8] => 9
[3] => 4
[7] => 8
[6] => 7
)
SortIterator
use Gielfeldt\Iterators\SortIterator; $input = new \ArrayIterator([6, 3, 2, 7, 1, 9]); $iterator = new SortIterator($input); print_r(iterator_to_array($iterator)); $input = new \ArrayIterator([6, 3, 2, 7, 1, 9]); $iterator = new SortIterator($input, SortIterator::SORT_DESC); print_r(iterator_to_array($iterator)); $input = new \ArrayIterator([6, 3, 2, 7, 1, 9]); $iterator = new SortIterator($input, SortIterator::SORT_ASC, SortIterator::SORT_REINDEX); print_r(iterator_to_array($iterator)); $input = new \ArrayIterator([6, 3, 2, 7, 1, 9]); $iterator = new SortIterator($input, SortIterator::SORT_ASC, SortIterator::SORT_REINDEX, function ($a, $b) { return -$a->current <=> -$b->current; }); print_r(iterator_to_array($iterator));
Output:
Array
(
[4] => 1
[2] => 2
[1] => 3
[0] => 6
[3] => 7
[5] => 9
)
Array
(
[5] => 9
[3] => 7
[0] => 6
[1] => 3
[2] => 2
[4] => 1
)
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 6
[4] => 7
[5] => 9
)
Array
(
[0] => 9
[1] => 7
[2] => 6
[3] => 3
[4] => 2
[5] => 1
)
StepIterator
Iterate over a traversable in steps.
use Gielfeldt\Iterators\StepIterator; $input = new \ArrayIterator(range(1, 10)); $stepped = new StepIterator($input, 2); print_r(iterator_to_array($stepped));
Output:
Array
(
[0] => 1
[2] => 3
[4] => 5
[6] => 7
[8] => 9
)
UniqueIterator
Similar to array_unique(). Also supports a custom callback function.
use Gielfeldt\Iterators\UniqueIterator; $input = new \ArrayIterator([-4, -3, -2, -1, 0, 1, 2, 3, 5]); // Unique elements by their square. $iterator = new UniqueIterator($input, UniqueIterator::REINDEX, function ($iterator) { return $iterator->current() * $iterator->current(); }); print_r(iterator_to_array($iterator));
Output:
Array
(
[0] => -4
[1] => -3
[2] => -2
[3] => -1
[4] => 0
[8] => 5
)
ValuesIterator
Similar to array_vales().
use Gielfeldt\Iterators\ValuesIterator; $input = new \ArrayIterator([ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', ]); $iterator = new ValuesIterator($input); print_r(iterator_to_array($iterator));
Output:
Array
(
[0] => value1
[1] => value2
[2] => value3
)
Not iterators as such ...
These are more an extension of the SPL file handling.
CsvFileObject
An extension of SplFileObject in csv mode, but with csv header support.
use Gielfeldt\Iterators\CsvFileObject; // Load csv file and dump it. $file = new CsvFileObject('somefile.csv'); print_r(iterator_to_array($file)); // Same but csv comes via a string variable. $csvdata = "Columm1,Column2\nValue1,Value2\nValue3,Value4"; $file = new CsvFileObject('data://application/octet,' . $csvdata); print_r(iterator_to_array($file));
Output:
Array
(
[0] => Array
(
[Columm1] => Value1
[Column2] => Value2
)
[1] => Array
(
[Columm1] => Value3
[Column2] => Value4
)
)
Array
(
[0] => Array
(
[Columm1] => Value1
[Column2] => Value2
)
[1] => Array
(
[Columm1] => Value3
[Column2] => Value4
)
)
AtomicTempFileObject
AtomicTempFileObjects
Helpers
Contains various helper methods.
Iterator
use Gielfeldt\Iterators\Iterator; $input = new \ArrayIterator([1,2,3,4,5,6]); var_dump(Iterator::sum($input)); var_dump(Iterator::product($input)); var_dump(Iterator::average($input)); var_dump(Iterator::min($input)); var_dump(Iterator::max($input));
Output:
int(21)
int(720)
double(3.5)
int(1)
int(6)
Caveats
- Lots probably.