Работа с итератори
Nette\Utils\Iterables е статичен клас с функции за работа с итератори. Неговият аналог за масиви е Nette\Utils\Arrays.
Инсталация:
composer require nette/utils
Всички примери предполагат създаден псевдоним:
use Nette\Utils\Iterables;
contains (iterable $iterable, $value): bool
Търси зададена стойност в итератора. Използва стриктно сравнение
(===
) за проверка на съвпадението. Връща true
, ако стойността
е намерена, в противен случай false
.
Iterables::contains(new ArrayIterator([1, 2, 3]), 1); // true
Iterables::contains(new ArrayIterator([1, 2, 3]), '1'); // false
Този метод е полезен, когато трябва бързо да разберете дали конкретна стойност се намира в итератора, без да се налага ръчно да преминавате през всички елементи.
containsKey (iterable $iterable, $key): bool
Търси зададен ключ в итератора. Използва стриктно сравнение
(===
) за проверка на съвпадението. Връща true
, ако ключът е
намерен, в противен случай false
.
Iterables::containsKey(new ArrayIterator([1, 2, 3]), 0); // true
Iterables::containsKey(new ArrayIterator([1, 2, 3]), 4); // false
every (iterable $iterable, callable $predicate): bool
Проверява дали всички елементи на итератора отговарят на условието,
дефинирано в $predicate
. Функцията $predicate
има сигнатура
function ($value, $key, iterable $iterable): bool
и трябва да връща true
за всеки
елемент, за да може методът every()
да върне true
.
$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isBelowThreshold = fn($value) => $value < 40;
$res = Iterables::every($iterator, $isBelowThreshold); // true
Този метод е полезен за проверка дали всички елементи в колекция отговарят на определено условие, например дали всички числа са по-малки от определена стойност.
filter (iterable $iterable, callable $predicate): Generator
Създава нов итератор, който съдържа само тези елементи от
оригиналния итератор, които отговарят на условието, дефинирано в
$predicate
. Функцията $predicate
има сигнатура
function ($value, $key, iterable $iterable): bool
и трябва да връща true
за
елементите, които трябва да бъдат запазени.
$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::filter($iterator, fn($v) => $v < 3);
// 1, 2
Методът използва генератор, което означава, че филтрирането се извършва постепенно при преминаване през резултата. Това е ефективно от гледна точка на паметта и позволява обработката дори на много големи колекции. Ако не преминете през всички елементи на резултантния итератор, ще спестите изчислителна мощ, тъй като не всички елементи от оригиналния итератор ще бъдат обработени.
first (iterable $iterable, ?callable $predicate=null, ?callable $else=null): mixed
Връща първия елемент на итератора. Ако е зададен $predicate
, връща
първия елемент, който отговаря на даденото условие. Функцията
$predicate
има сигнатура function ($value, $key, iterable $iterable): bool
. Ако не е
намерен отговарящ елемент, се извиква функцията $else
(ако е
зададена) и се връща нейният резултат. Ако $else
не е зададено, се
връща null
.
Iterables::first(new ArrayIterator([1, 2, 3])); // 1
Iterables::first(new ArrayIterator([1, 2, 3]), fn($v) => $v > 2); // 3
Iterables::first(new ArrayIterator([])); // null
Iterables::first(new ArrayIterator([]), else: fn() => false); // false
Този метод е полезен, когато трябва бързо да получите първия елемент на колекция или първия елемент, отговарящ на определено условие, без да се налага ръчно да преминавате през цялата колекция.
firstKey (iterable $iterable, ?callable $predicate=null, ?callable $else=null): mixed
Връща ключа на първия елемент на итератора. Ако е зададен
$predicate
, връща ключа на първия елемент, който отговаря на даденото
условие. Функцията $predicate
има сигнатура
function ($value, $key, iterable $iterable): bool
. Ако не е намерен отговарящ елемент,
се извиква функцията $else
(ако е зададена) и се връща нейният
резултат. Ако $else
не е зададено, се връща null
.
Iterables::firstKey(new ArrayIterator([1, 2, 3])); // 0
Iterables::firstKey(new ArrayIterator([1, 2, 3]), fn($v) => $v > 2); // 2
Iterables::firstKey(new ArrayIterator(['a' => 1, 'b' => 2])); // 'a'
Iterables::firstKey(new ArrayIterator([])); // null
map (iterable $iterable, callable $transformer): Generator
Създава нов итератор чрез прилагане на функцията $transformer
към
всеки елемент на оригиналния итератор. Функцията $transformer
има
сигнатура function ($value, $key, iterable $iterable): mixed
и нейната върната
стойност се използва като нова стойност на елемента.
$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::map($iterator, fn($v) => $v * 2);
// 2, 4, 6
Методът използва генератор, което означава, че трансформацията се извършва постепенно при преминаване през резултата. Това е ефективно от гледна точка на паметта и позволява обработката дори на много големи колекции. Ако не преминете през всички елементи на резултантния итератор, ще спестите изчислителна мощ, тъй като не всички елементи от оригиналния итератор ще бъдат обработени.
mapWithKeys (iterable $iterable, callable $transformer): Generator
Създава нов итератор чрез трансформация на стойностите и ключовете
на оригиналния итератор. Функцията $transformer
има сигнатура
function ($value, $key, iterable $iterable): ?array{$newKey, $newValue}
. Ако $transformer
върне
null
, елементът се пропуска. За запазените елементи първият
елемент на върнатия масив се използва като нов ключ, а вторият елемент
като нова стойност.
$iterator = new ArrayIterator(['a' => 1, 'b' => 2]);
$iterator = Iterables::mapWithKeys($iterator, fn($v, $k) => $v > 1 ? [$v * 2, strtoupper($k)] : null);
// [4 => 'B']
Подобно на map()
, този метод използва генератор за постепенно
обработване и ефективна работа с паметта. Това позволява работа с
големи колекции и спестяване на изчислителна мощ при частично
преминаване през резултата.
memoize (iterable $iterable): IteratorAggregate
Създава обвивка около итератора, която по време на итерация кешира неговите ключове и стойности. Това позволява повторна итерация на данните без необходимост от повторно преминаване през оригиналния източник на данни.
$iterator = /* данни, които не могат да бъдат итерирани повече от веднъж */
$memoized = Iterables::memoize($iterator);
// Сега можете да итерирате $memoized многократно без загуба на данни
Този метод е полезен в ситуации, когато трябва да преминете многократно през един и същ набор от данни, но оригиналният итератор не позволява повторна итерация или повторното преминаване би било скъпо (напр. при четене на данни от база данни или файл).
some (iterable $iterable, callable $predicate): bool
Проверява дали поне един елемент на итератора отговаря на условието,
дефинирано в $predicate
. Функцията $predicate
има сигнатура
function ($value, $key, iterable $iterable): bool
и трябва да връща true
за поне
един елемент, за да може методът some()
да върне true
.
$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isEven = fn($value) => $value % 2 === 0;
$res = Iterables::some($iterator, $isEven); // true
Този метод е полезен за бърза проверка дали в колекцията съществува поне един елемент, отговарящ на определено условие, например дали колекцията съдържа поне едно четно число.
Вижте every().
toIterator (iterable $iterable): Iterator
Преобразува всеки итерируем обект (array, Traversable) в Iterator. Ако входът вече е Iterator, го връща без промяна.
$array = [1, 2, 3];
$iterator = Iterables::toIterator($array);
// Сега имате Iterator вместо масив
Този метод е полезен, когато трябва да се уверите, че разполагате с Iterator, независимо от типа на входните данни. Това може да бъде полезно при създаване на функции, които работят с различни типове итерируеми данни.