Работа с итератори

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, независимо от типа на входните данни. Това може да бъде полезно при създаване на функции, които работят с различни типове итерируеми данни.

версия: 4.0