talesoft / tale-iterator
一个基本的、PSR-7 兼容的流实用程序库
Requires
- php: >=7.1.0
Requires (Dev)
- talesoft/tale-dev-tool: 0.2.2
This package is auto-updated.
Last update: 2024-09-10 08:04:48 UTC
README
Tale Iterator
什么是 Tale Iterator?
Tale Iterator 通过一些更实用的迭代器扩展了 SPL 迭代器,适用于常见用例。
安装
composer require talesoft/tale-iterator
使用
MapIterator
通过 map()
方法映射值。你通常想要扩展它并重写 map()
方法。
使用 FlipIterator
栈来映射键(见本 README 底部的 "如何做 XYZ")
use Tale\Iterator\MapIterator; $values = new \ArrayIterator(range(0, 5)); $mapper = new class($values) extends MapIterator { public function map() { return sprintf('Value %d', parent::map()); } }; var_dump(iterator_to_array($mapper)); /* array(6) { [0] => string(7) "Value 0" [1] => string(7) "Value 1" [2] => string(7) "Value 2" [3] => string(7) "Value 3" [4] => string(7) "Value 4" [5] => string(7) "Value 5" } */
CallbackMapIterator
通过指定一个简单的回调来映射值。
使用 FlipIterator
栈来映射键(见本 README 底部的 "如何做 XYZ")
use Tale\Iterator\CallbackMapIterator; $values = new \ArrayIterator(range(0, 5)); $mapper = new CallbackMapIterator($values, function (int $number) { return sprintf('Value %d', $number); }); var_dump(iterator_to_array($mapper)); /* array(6) { [0] => string(7) "Value 0" [1] => string(7) "Value 1" [2] => string(7) "Value 2" [3] => string(7) "Value 3" [4] => string(7) "Value 4" [5] => string(7) "Value 5" } */
FilterIterator
通过 accept()
方法过滤值。你通常想要扩展它并重写 accept()
方法。**它将保留键**!如果你想重置键,请按照以下示例链式一个 ValueIterator
。
使用 FlipIterator
栈来过滤键(见本 README 底部的 "如何做 XYZ")
use Tale\Iterator\FilterIterator; $values = new \ArrayIterator(range(0, 5)); $filterer = new class($values) extends FilterIterator { public function accept(): bool { return parent::current() !== 4; } }; var_dump(iterator_to_array($filterer)); /* array(5) { [0] => string(7) "Value 0" [1] => string(7) "Value 1" [2] => string(7) "Value 2" [3] => string(7) "Value 3" [5] => string(7) "Value 5" } */
CallbackFilterIterator
通过指定一个简单的回调来过滤值。
使用 FlipIterator
栈来过滤键(见本 README 底部的 "如何做 XYZ")
use Tale\Iterator\CallbackFilterIterator; $values = new \ArrayIterator(range(0, 5)); $filterer = new CallbackFilterIterator($values, function (int $number) { return $number !== 3; }); var_dump(iterator_to_array($filterer)); /* array(5) { [0] => string(7) "Value 0" [1] => string(7) "Value 1" [2] => string(7) "Value 2" [4] => string(7) "Value 4" [5] => string(7) "Value 5" } */
注意
PHP 已经有了 FilterIterator 和 CallbackFilterIterator,但它只接受 \Iterator 的实例,不包括 \IteratorAggregate 实例。这个接受 \Traversable 的实例,它包括所有可迭代的对象(包括对象和原生数组,也在此范围内)。尽管如此,它仍然使用与 PHP 实现相同的 API!
IterableIterator
这是一个将任何 iterable
转换为有效迭代器的小型实用程序迭代器。它相当于一个 \IteratorIterator,它将传递的可迭代对象标准化为
$iterable instanceof \Traversable ? $iterable : new \ArrayIterator($iterable)
.
使用这个迭代器,你可以轻松地将任何类型的可迭代对象(如数组、对象、生成器等)传递给只接受 \Iterator 实例的迭代器。
这对于 PHP 的 SPL 迭代器或其他只利用 iterable
或 \Traversable
并仅依赖于 \Iterator
的迭代器实现非常有用,或者出于非常好的原因这样做。
use Tale\Iterator\IterableIterator; $values = new IterableIterator(['a', 'b', 'c', 'd', 'e']); $filterer = new \RegexIterator($values, '/[a-c]/'); var_dump(iterator_to_array($filterer)); /* array(3) { [0] => string(1) "a" [1] => string(1) "b" [2] => string(1) "c" } */
ValueIterator
这是迭代器的 array_values()
。这对于重置 FilterIterator
输出的键非常有用。
use Tale\Iterator\CallbackFilterIterator; use Tale\Iterator\ValueIterator; $values = new \ArrayIterator(range(0, 5)); $filterer = new CallbackFilterIterator($values, function (int $number) { return $number !== 3; }); $resetter = new ValueIterator($filterer); var_dump(iterator_to_array($resetter)); /* array(5) { [0] => string(7) "Value 0" [1] => string(7) "Value 1" [2] => string(7) "Value 2" [3] => string(7) "Value 4" [4] => string(7) "Value 5" } Compare the output to the CallbackFilterIterator example above and notice the keys! */
KeyIterator
这是迭代器的 array_keys()
。如果你想得到内部迭代器键的干净列表,这非常有用。
use Tale\Iterator\KeyIterator; $values = new \ArrayIterator(['a' => 1, 'b' => 2, 'c' => 3]); $keys = new KeyIterator($values); var_dump(iterator_to_array($keys)); /* array(3) { [0] => string(1) "a" [1] => string(1) "b" [2] => string(1) "c" } Compare the output to the CallbackFilterIterator example above and notice the keys! */
FlipIterator
这个迭代器将键和值翻转。如果你想让外部迭代器在键上而不是在值上操作,这通常很有用。
由于迭代器的工作方式,只要你没有将迭代器展开为数组,重复的值不会导致键丢失!注意第二个示例来理解我的意思。
use Tale\Iterator\FlipIterator; $values = new \ArrayIterator(range('a', 'e')); $flipper = new FlipIterator($values); var_dump(iterator_to_array($flipper)); /* array(5) { 'a' => int(0) 'b' => int(1) 'c' => int(2) 'd' => int(3) 'e' => int(4) } */
使用 array_flip
,重复的值会导致键丢失,因为数组键必须是唯一的。对于迭代器来说,只要你不实际展开它,这种情况就不会发生!
use Tale\Iterator\FlipIterator; $values = new \ArrayIterator(['a' => 1, 'b' => 2, 'c' => 2, 'd' => 2]); $flipper = new FlipIterator($values); //Do something with $flipper, like, iterator stuff $reverseFlipper = new FlipIterator($flipper); var_dump(iterator_to_array($reverseFlipper)); /* array(4) { 'a' => int(1) 'b' => int(2) 'c' => int(2) 'd' => int(2) } */
FormatIterator
这是迭代器中每个值的 sprintf($format, $current)
。
使用 FlipIterator
栈来格式化键(见本 README 底部的 "如何做 XYZ")
use Tale\Iterator\FormatIterator; $values = new \ArrayIterator(range(0, 5)); $formatter = new FormatIterator($values, 'Value %d'); var_dump(iterator_to_array($formatter)); /* array(6) { [0] => string(7) "Value 0" [1] => string(7) "Value 1" [2] => string(7) "Value 2" [3] => string(7) "Value 3" [4] => string(7) "Value 4" [5] => string(7) "Value 5" } */
PrefixIterator
这是迭代器中每个值的 $prefix.$current
。
使用 FlipIterator
栈来前缀键(见本 README 底部的 "如何做 XYZ")
use Tale\Iterator\PrefixIterator; $values = new \ArrayIterator(range(0, 5)); $prefixer = new PrefixIterator($values, 'Value '); var_dump(iterator_to_array($prefixer)); /* array(6) { [0] => string(7) "Value 0" [1] => string(7) "Value 1" [2] => string(7) "Value 2" [3] => string(7) "Value 3" [4] => string(7) "Value 4" [5] => string(7) "Value 5" } */
SuffixIterator
这是迭代器中每个值的 $current.$suffix
。
使用FlipIterator
将后缀键堆叠(参见本README底部“如何进行XYZ”)
use Tale\Iterator\SuffixIterator; $values = new \ArrayIterator(range(0, 5)); $suffixer = new SuffixIterator($values, ' Value'); var_dump(iterator_to_array($suffixer)); /* array(11) { [0] => string(7) "0 Value" [1] => string(7) "1 Value" [2] => string(7) "2 Value" [3] => string(7) "3 Value" [4] => string(7) "4 Value" [5] => string(7) "5 Value" } */
IndexIterator
这个迭代器在迭代过程中计算一个独立的索引并将其提供出来。这通常用于计算迭代的次数。ValueIterator
和KeyIterator
使用这个来重置键。
use Tale\Iterator\IndexIterator; $values = new \ArrayIterator(['a' => 'b', 'b' => 'c', 'c' => 'd']); $indexer = new IndexIterator($values); foreach ($indexer as $key => $value) { $i = $indexer->getIndex(); echo "{$key} => {$value} - at index: {$i}\n"; } /* a => b - at index: 0 b => c - at index: 1 c => d - at index: 2 */
如何进行XYZ?
如何映射键而不是值?
很简单,通过链式连接MapIterator和FlipIterators!注意这不会产生任何额外的开销,除了函数调用。内部数组根本不会被复制或修改。
use Tale\Iterator\FlipIterator; use Tale\Iterator\CallbackMapIterator; $values = new \ArrayIterator(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]); $mapper = new FlipIterator( new CallbackMapIterator( new FlipIterator($values), function (string $key) { return "Key {$key}"; } ) ); var_dump(iterator_to_array($mapper)); /* array(4) { 'Key a' => int(1) 'Key b' => int(2) 'Key c' => int(3) 'Key d' => int(4) } */
如何过滤键而不是值?
在这里,FlipIterator同样可以做你需要的一切!
use Tale\Iterator\FlipIterator; use Tale\Iterator\CallbackFilterIterator; $values = new \ArrayIterator(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]); $mapper = new FlipIterator( new CallbackFilterIterator( new FlipIterator($values), function (string $key) { return $key !== 'b'; } ) ); var_dump(iterator_to_array($mapper)); /* array(4) { 'a' => int(1) 'c' => int(3) 'd' => int(4) } */