gielfeldt/iterators

0.2.0 2018-11-04 00:27 UTC

This package is not auto-updated.

Last update: 2024-09-19 12:31:50 UTC


README

Build Status Test Coverage Code Climate Scrutinizer Code Quality

Latest Stable Version Latest Unstable Version Dependency Status License Total Downloads

Documentation Status Documentation Status

安装

composer require gielfeldt/iterators

迭代器

这个库包含了一系列各种迭代器,我主要是为了更好地了解PHP中的迭代器而编写的。其中一些可能有用,而另一些可能很愚蠢。

享受吧!

CachingIterator

ChecksumIterator

ChunkIterator

CloningIterator

CombineIterator

CountableIterator

DiffIterator

FiniteIterator

FlipIterator

GlobIterator

IndexIterator

InfiniteIterator

InterleaveIterator

IntersectIterator

TraversableIterator

KeysIterator

MapIterator

RandomIterator

RepeatIterator

ReplaceableIterator

ReservoirSamplingIterator

ShuffleIterator

SortIterator

StepIterator

UniqueIterator

ValuesIterator

CachingIterator

缓存迭代器以进行多次迭代。

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));

输出

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
)
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
)

ChecksumIterator

为迭代器生成校验和,可以是每次迭代或整个数据集。

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);

输出

0 => e2e517365ffe6fedd279364e3fa74786
1 => f0a0db0fc9abe193b21fd657fe678884
2 => c04f606bb5bba82282dfa93edb59c6ee

string(32) "4fd19adc845da6fdd9c7c394f4626bac"

string(32) "4fd19adc845da6fdd9c7c394f4626bac"

ChunkIterator

将迭代器分割成迭代器的块。

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

克隆迭代中的每个值。

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);

输出

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

类似于array_combine()。然而,迭代器可以有非唯一键。在使用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));

输出

key1 => value1
key2 => value2
key3 => value3
key1 => value4
key2 => value5
key3 => value6
Array
(
    [key1] => value4
    [key2] => value5
    [key3] => value6
)

CountableIterator

通过迭代并计数使其可计数的任何迭代器。

use Gielfeldt\Iterators\CountableIterator;

$some_noncountable_iterator = new \IteratorIterator(new \ArrayIterator([1, 2, 3]));
$iterator = new CountableIterator($some_noncountable_iterator);
var_dump(count($iterator));

输出

int(3)

DiffIterator

比较两个迭代器。类似于array_diff()。可以设置自定义比较函数。

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));

输出

Array
(
    [key1] => value1
    [key3] => value3
)

FiniteIterator

通过匿名函数为迭代器提供一个结束条件。

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));

输出

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
)

FlipIterator

类似于array_flip()。然而,迭代器可以有非唯一键。在使用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));

输出

value1 => key1
value2 => key2
value3 => key3
value1 => key4
value2 => key5
value3 => key6
Array
(
    [value1] => key4
    [value2] => key5
    [value3] => key6
)

GlobIterator

类似于\GlobIterator,但支持**

use Gielfeldt\Iterators\GlobIterator;

$iterator = new GlobIterator('/tmp/**.log');
var_dump(iterator_to_array($iterator));

输出

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

仅遍历迭代器的某些行。

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));

输出

Array
(
    [test3] => val4
    [test4] => val3
    [test6] => val1
)

InfiniteIterator

类似于SPL的InfiniteIterator,但提供了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";
}

输出

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

交错多个迭代器。

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));

输出

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

类似于array_intersect()。可以设置自定义比较函数。

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));

输出

Array
(
    [key1] => value1
)

TraversableIterator

类似于SPL的IteratorIterator,但有一个更有意义的名字:-)并提供getIndex()方法。

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";
}

输出

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

类似于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));

输出

Array
(
    [0] => key1
    [1] => key2
    [2] => key3
)

MapIterator

类似于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));

输出

value1 => key1
value2 => key2
value3 => key3
value1 => key4
value2 => key5
value3 => key6
Array
(
    [value1] => key4
    [value2] => key5
    [value3] => key6
)

RandomIterator

从可遍历的集合中选择一组随机元素。不适用于只能遍历一次的迭代器。请参阅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));

输出

int(4)
Array
(
    [1] => 2
    [6] => 7
    [7] => 8
    [8] => 9
)

RepeatIterator

重复迭代器n次。

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));

输出

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

类似于TraversableIterator,但具有setInnerIterator()方法。

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));

输出

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
)
Array
(
    [0] => 5
    [1] => 6
    [2] => 7
    [3] => 8
)

ReservoirSamplingIterator

类似于RandomIterator,但更有效地处理未知大小或只能遍历一次的迭代器。

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));

输出

int(4)
Array
(
    [1] => 2
    [6] => 7
    [7] => 8
    [8] => 9
)

ShuffleIterator

随机遍历可遍历的集合。

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));

输出

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));

输出

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

以步长遍历可遍历的集合。

use Gielfeldt\Iterators\StepIterator;

$input = new \ArrayIterator(range(1, 10));
$stepped = new StepIterator($input, 2);

print_r(iterator_to_array($stepped));

输出

Array
(
    [0] => 1
    [2] => 3
    [4] => 5
    [6] => 7
    [8] => 9
)

UniqueIterator

类似于array_unique()。也支持自定义回调函数。

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));

输出

Array
(
    [0] => -4
    [1] => -3
    [2] => -2
    [3] => -1
    [4] => 0
    [8] => 5
)

ValuesIterator

类似于array_values()。

use Gielfeldt\Iterators\ValuesIterator;

$input = new \ArrayIterator([
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3',
]);

$iterator = new ValuesIterator($input);

print_r(iterator_to_array($iterator));

输出

Array
(
    [0] => value1
    [1] => value2
    [2] => value3
)

不是迭代器...

这些都是SPL文件处理的扩展。

CsvFileObject

AtomicTempFileObject

AtomicTempFileObjects

CsvFileObject

是SplFileObject在csv模式下的扩展,但支持csv头。

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));

输出

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

辅助函数

包含各种辅助方法。

迭代器

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));

输出

int(21)

int(720)

double(3.5)

int(1)

int(6)

注意事项

  1. 可能有很多。