Nette Documentation Preview

syntax
Praca z iteratorami
*******************

.[perex]{data-version:4.0.4}
[api:Nette\Utils\Iterables] to klasa statyczna z funkcjami do pracy z iteratorami. Jej odpowiednikiem dla tablic jest [Nette\Utils\Arrays|arrays].


Instalacja:

```shell
composer require nette/utils
```

Wszystkie przykłady zakładają, że utworzony jest następujący alias:

```php
use Nette\Utils\Iterables;
```


contains(iterable $iterable, $value): bool .[method]
----------------------------------------------------

Szuka podanej wartości w iteratorze. Do sprawdzenia zgodności używa porównania ścisłego (`===`). Zwraca `true`, jeśli wartość zostanie znaleziona, w przeciwnym razie `false`.

```php
Iterables::contains(new ArrayIterator([1, 2, 3]), 1);    // true
Iterables::contains(new ArrayIterator([1, 2, 3]), '1');  // false
```

Ta metoda przydaje się, gdy potrzebujesz szybko ustalić, czy w iteratorze istnieje konkretna wartość, bez ręcznego przechodzenia przez wszystkie elementy.


containsKey(iterable $iterable, $key): bool .[method]
-----------------------------------------------------

Szuka podanego klucza w iteratorze. Do sprawdzenia zgodności używa porównania ścisłego (`===`). Zwraca `true`, jeśli klucz zostanie znaleziony, w przeciwnym razie `false`.

```php
Iterables::containsKey(new ArrayIterator([1, 2, 3]), 0);  // true
Iterables::containsKey(new ArrayIterator([1, 2, 3]), 4);  // false
```


every(iterable $iterable, callable $predicate): bool .[method]
--------------------------------------------------------------

Sprawdza, czy wszystkie elementy iteratora spełniają warunek zdefiniowany w `$predicate`. Callback `$predicate` ma sygnaturę `function ($value, $key, iterable $iterable): bool` i musi zwrócić `true` dla każdego elementu, aby metoda `every()` zwróciła `true`.

```php
$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isBelowThreshold = fn($value) => $value < 40;
$res = Iterables::every($iterator, $isBelowThreshold); // true
```

Ta metoda przydaje się do sprawdzenia, czy wszystkie elementy kolekcji spełniają określony warunek, na przykład czy wszystkie liczby są mniejsze od konkretnej wartości.


filter(iterable $iterable, callable $predicate): Generator .[method]
--------------------------------------------------------------------

Tworzy nowy iterator zawierający tylko te elementy pierwotnego iteratora, które spełniają warunek zdefiniowany w `$predicate`. Callback `$predicate` ma sygnaturę `function ($value, $key, iterable $iterable): bool` i musi zwrócić `true` dla elementów, które mają zostać zachowane.

```php
$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::filter($iterator, fn($v) => $v < 3);
// 1, 2
```

Metoda używa generatora, co oznacza, że filtrowanie zachodzi stopniowo, w miarę przechodzenia po wyniku. Jest to oszczędne pamięciowo i pozwala przetwarzać bardzo duże kolekcje. Jeśli nie przejdziesz po wszystkich elementach wynikowego iteratora, oszczędzasz moc obliczeniową, bo nie wszystkie elementy pierwotnego iteratora zostaną przetworzone.


first(iterable $iterable, ?callable $predicate=null, ?callable $else=null): mixed .[method]
-------------------------------------------------------------------------------------------

Zwraca pierwszy element iteratora. Jeśli podano `$predicate`, zwraca pierwszy element spełniający warunek. Callback `$predicate` ma sygnaturę `function ($value, $key, iterable $iterable): bool`. Jeśli żaden pasujący element się nie znajdzie, wywoływany jest callback `$else` (o ile go podano) i zwracany jest jego wynik. Jeśli `$else` nie podano, zwracane jest `null`.

```php
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
```

Ta metoda przydaje się, gdy potrzebujesz szybko pobrać pierwszy element kolekcji albo pierwszy element spełniający konkretny warunek, bez ręcznego przechodzenia przez całą kolekcję.


firstKey(iterable $iterable, ?callable $predicate=null, ?callable $else=null): mixed .[method]
----------------------------------------------------------------------------------------------

Zwraca klucz pierwszego elementu iteratora. Jeśli podano `$predicate`, zwraca klucz pierwszego elementu spełniającego warunek. Callback `$predicate` ma sygnaturę `function ($value, $key, iterable $iterable): bool`. Jeśli żaden pasujący element się nie znajdzie, wywoływany jest callback `$else` (o ile go podano) i zwracany jest jego wynik. Jeśli `$else` nie podano, zwracane jest `null`.

```php
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 .[method]
-------------------------------------------------------------------

Tworzy nowy iterator, stosując callback `$transformer` do każdego elementu pierwotnego iteratora. Callback `$transformer` ma sygnaturę `function ($value, $key, iterable $iterable): mixed`, a zwracana przez niego wartość jest używana jako nowa wartość elementu.

```php
$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::map($iterator, fn($v) => $v * 2);
// 2, 4, 6
```

Metoda używa generatora, co oznacza, że przekształcanie zachodzi stopniowo, w miarę przechodzenia po wyniku. Jest to oszczędne pamięciowo i pozwala przetwarzać bardzo duże kolekcje. Jeśli nie przejdziesz po wszystkich elementach wynikowego iteratora, oszczędzasz moc obliczeniową, bo nie wszystkie elementy pierwotnego iteratora zostaną przetworzone.


mapWithKeys(iterable $iterable, callable $transformer): Generator .[method]
---------------------------------------------------------------------------

Tworzy nowy iterator, przekształcając wartości i klucze pierwotnego iteratora. Callback `$transformer` ma sygnaturę `function ($value, $key, iterable $iterable): ?array{$newKey, $newValue}`. Jeśli `$transformer` zwróci `null`, element zostanie pominięty. Dla zachowanych elementów pierwszy element zwróconej tablicy jest używany jako nowy klucz, a drugi jako nowa wartość.

```php
$iterator = new ArrayIterator(['a' => 1, 'b' => 2]);
$iterator = Iterables::mapWithKeys($iterator, fn($v, $k) => $v > 1 ? [$v * 2, strtoupper($k)] : null);
// [4 => 'B']
```

Podobnie jak `map()`, ta metoda używa generatora do przetwarzania stopniowego i oszczędności pamięci. Pozwala to pracować z dużymi kolekcjami i oszczędzać moc obliczeniową przy tylko częściowym przejściu po wyniku.


memoize(iterable $iterable): IteratorAggregate .[method]
--------------------------------------------------------

Tworzy wrapper wokół iteratora, który podczas iteracji cachuje jego klucze i wartości. Pozwala to wielokrotnie przechodzić po danych bez konieczności ponownego przechodzenia po pierwotnym źródle danych.

```php
$iterator = /* ... */; // dane, po których nie da się iterować wielokrotnie
$memoized = Iterables::memoize($iterator);
// teraz możesz iterować po $memoized wiele razy bez utraty danych
```

Ta metoda przydaje się w sytuacjach, gdy potrzebujesz kilkakrotnie przejść po tym samym zestawie danych, ale pierwotny iterator nie pozwala na wielokrotną iterację albo ponowne przejście byłoby kosztowne (np. odczyt danych z bazy danych albo pliku).


repeatable(callable $factory): IteratorAggregate .[method]{data-version:4.0.10}
-------------------------------------------------------------------------------

Pozwala wielokrotnie iterować po obiektach, które normalnie tego nie obsługują, typowo po [generatorach PHP |https://www.php.net/manual/en/language.generators.overview.php]. Metoda `repeatable()` rozwiązuje ten problem elegancko: zamiast przekazywać sam iterator, przekazujesz funkcję, która go tworzy. Ta fabryka jest potem automatycznie wywoływana przy każdej pętli iteracyjnej.

```php
// zwykły generator, po którym nie da się iterować dwa razy
$generator = function () {
	yield 'A';
	yield 'B';
};

$iterator = Iterables::repeatable($generator);

foreach ($iterator as $v) echo $v; // wypisze: AB
foreach ($iterator as $v) echo $v; // wypisze: AB (generator uruchomił się ponownie)
```

Ta metoda jest alternatywą dla [#memoize()] w sytuacjach, gdy pracujesz z **dużymi ilościami danych**, bo `repeatable()` nie cachuje danych, lecz generuje je ponownie przy każdej iteracji.


some(iterable $iterable, callable $predicate): bool .[method]
-------------------------------------------------------------

Sprawdza, czy co najmniej jeden element iteratora spełnia warunek zdefiniowany w `$predicate`. Callback `$predicate` ma sygnaturę `function ($value, $key, iterable $iterable): bool` i musi zwrócić `true` dla co najmniej jednego elementu, aby metoda `some()` zwróciła `true`.

```php
$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isEven = fn($value) => $value % 2 === 0;
$res = Iterables::some($iterator, $isEven); // true
```

Ta metoda przydaje się do szybkiego sprawdzenia, czy co najmniej jeden element kolekcji spełnia określony warunek, na przykład czy kolekcja zawiera co najmniej jedną liczbę parzystą.

Zobacz [#every()].


toIterator(iterable $iterable): Iterator .[method]
--------------------------------------------------

Konwertuje dowolny obiekt iterowalny (tablicę, Traversable) na Iterator. Jeśli wejściem jest już Iterator, zwracany jest bez zmian.

```php
$array = [1, 2, 3];
$iterator = Iterables::toIterator($array);
// teraz masz Iterator zamiast tablicy
```

Ta metoda przydaje się, gdy potrzebujesz mieć pewność, że dysponujesz Iteratorem, niezależnie od typu danych wejściowych. Bywa to pomocne przy tworzeniu funkcji pracujących z różnymi typami danych iterowalnych.

Praca z iteratorami

Nette\Utils\Iterables to klasa statyczna z funkcjami do pracy z iteratorami. Jej odpowiednikiem dla tablic jest Nette\Utils\Arrays.

Instalacja:

composer require nette/utils

Wszystkie przykłady zakładają, że utworzony jest następujący alias:

use Nette\Utils\Iterables;

contains(iterable $iterable, $value)bool

Szuka podanej wartości w iteratorze. Do sprawdzenia zgodności używa porównania ścisłego (===). Zwraca true, jeśli wartość zostanie znaleziona, w przeciwnym razie false.

Iterables::contains(new ArrayIterator([1, 2, 3]), 1);    // true
Iterables::contains(new ArrayIterator([1, 2, 3]), '1');  // false

Ta metoda przydaje się, gdy potrzebujesz szybko ustalić, czy w iteratorze istnieje konkretna wartość, bez ręcznego przechodzenia przez wszystkie elementy.

containsKey(iterable $iterable, $key)bool

Szuka podanego klucza w iteratorze. Do sprawdzenia zgodności używa porównania ścisłego (===). Zwraca true, jeśli klucz zostanie znaleziony, w przeciwnym razie 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

Sprawdza, czy wszystkie elementy iteratora spełniają warunek zdefiniowany w $predicate. Callback $predicate ma sygnaturę function ($value, $key, iterable $iterable): bool i musi zwrócić true dla każdego elementu, aby metoda every() zwróciła true.

$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isBelowThreshold = fn($value) => $value < 40;
$res = Iterables::every($iterator, $isBelowThreshold); // true

Ta metoda przydaje się do sprawdzenia, czy wszystkie elementy kolekcji spełniają określony warunek, na przykład czy wszystkie liczby są mniejsze od konkretnej wartości.

filter(iterable $iterable, callable $predicate): Generator

Tworzy nowy iterator zawierający tylko te elementy pierwotnego iteratora, które spełniają warunek zdefiniowany w $predicate. Callback $predicate ma sygnaturę function ($value, $key, iterable $iterable): bool i musi zwrócić true dla elementów, które mają zostać zachowane.

$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::filter($iterator, fn($v) => $v < 3);
// 1, 2

Metoda używa generatora, co oznacza, że filtrowanie zachodzi stopniowo, w miarę przechodzenia po wyniku. Jest to oszczędne pamięciowo i pozwala przetwarzać bardzo duże kolekcje. Jeśli nie przejdziesz po wszystkich elementach wynikowego iteratora, oszczędzasz moc obliczeniową, bo nie wszystkie elementy pierwotnego iteratora zostaną przetworzone.

first(iterable $iterable, ?callable $predicate=null, ?callable $else=null)mixed

Zwraca pierwszy element iteratora. Jeśli podano $predicate, zwraca pierwszy element spełniający warunek. Callback $predicate ma sygnaturę function ($value, $key, iterable $iterable): bool. Jeśli żaden pasujący element się nie znajdzie, wywoływany jest callback $else (o ile go podano) i zwracany jest jego wynik. Jeśli $else nie podano, zwracane jest 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

Ta metoda przydaje się, gdy potrzebujesz szybko pobrać pierwszy element kolekcji albo pierwszy element spełniający konkretny warunek, bez ręcznego przechodzenia przez całą kolekcję.

firstKey(iterable $iterable, ?callable $predicate=null, ?callable $else=null)mixed

Zwraca klucz pierwszego elementu iteratora. Jeśli podano $predicate, zwraca klucz pierwszego elementu spełniającego warunek. Callback $predicate ma sygnaturę function ($value, $key, iterable $iterable): bool. Jeśli żaden pasujący element się nie znajdzie, wywoływany jest callback $else (o ile go podano) i zwracany jest jego wynik. Jeśli $else nie podano, zwracane jest 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

Tworzy nowy iterator, stosując callback $transformer do każdego elementu pierwotnego iteratora. Callback $transformer ma sygnaturę function ($value, $key, iterable $iterable): mixed, a zwracana przez niego wartość jest używana jako nowa wartość elementu.

$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::map($iterator, fn($v) => $v * 2);
// 2, 4, 6

Metoda używa generatora, co oznacza, że przekształcanie zachodzi stopniowo, w miarę przechodzenia po wyniku. Jest to oszczędne pamięciowo i pozwala przetwarzać bardzo duże kolekcje. Jeśli nie przejdziesz po wszystkich elementach wynikowego iteratora, oszczędzasz moc obliczeniową, bo nie wszystkie elementy pierwotnego iteratora zostaną przetworzone.

mapWithKeys(iterable $iterable, callable $transformer): Generator

Tworzy nowy iterator, przekształcając wartości i klucze pierwotnego iteratora. Callback $transformer ma sygnaturę function ($value, $key, iterable $iterable): ?array{$newKey, $newValue}. Jeśli $transformer zwróci null, element zostanie pominięty. Dla zachowanych elementów pierwszy element zwróconej tablicy jest używany jako nowy klucz, a drugi jako nowa wartość.

$iterator = new ArrayIterator(['a' => 1, 'b' => 2]);
$iterator = Iterables::mapWithKeys($iterator, fn($v, $k) => $v > 1 ? [$v * 2, strtoupper($k)] : null);
// [4 => 'B']

Podobnie jak map(), ta metoda używa generatora do przetwarzania stopniowego i oszczędności pamięci. Pozwala to pracować z dużymi kolekcjami i oszczędzać moc obliczeniową przy tylko częściowym przejściu po wyniku.

memoize(iterable $iterable): IteratorAggregate

Tworzy wrapper wokół iteratora, który podczas iteracji cachuje jego klucze i wartości. Pozwala to wielokrotnie przechodzić po danych bez konieczności ponownego przechodzenia po pierwotnym źródle danych.

$iterator = /* ... */; // dane, po których nie da się iterować wielokrotnie
$memoized = Iterables::memoize($iterator);
// teraz możesz iterować po $memoized wiele razy bez utraty danych

Ta metoda przydaje się w sytuacjach, gdy potrzebujesz kilkakrotnie przejść po tym samym zestawie danych, ale pierwotny iterator nie pozwala na wielokrotną iterację albo ponowne przejście byłoby kosztowne (np. odczyt danych z bazy danych albo pliku).

repeatable(callable $factory): IteratorAggregate

Pozwala wielokrotnie iterować po obiektach, które normalnie tego nie obsługują, typowo po generatorach PHP. Metoda repeatable() rozwiązuje ten problem elegancko: zamiast przekazywać sam iterator, przekazujesz funkcję, która go tworzy. Ta fabryka jest potem automatycznie wywoływana przy każdej pętli iteracyjnej.

// zwykły generator, po którym nie da się iterować dwa razy
$generator = function () {
	yield 'A';
	yield 'B';
};

$iterator = Iterables::repeatable($generator);

foreach ($iterator as $v) echo $v; // wypisze: AB
foreach ($iterator as $v) echo $v; // wypisze: AB (generator uruchomił się ponownie)

Ta metoda jest alternatywą dla memoize() w sytuacjach, gdy pracujesz z dużymi ilościami danych, bo repeatable() nie cachuje danych, lecz generuje je ponownie przy każdej iteracji.

some(iterable $iterable, callable $predicate)bool

Sprawdza, czy co najmniej jeden element iteratora spełnia warunek zdefiniowany w $predicate. Callback $predicate ma sygnaturę function ($value, $key, iterable $iterable): bool i musi zwrócić true dla co najmniej jednego elementu, aby metoda some() zwróciła true.

$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isEven = fn($value) => $value % 2 === 0;
$res = Iterables::some($iterator, $isEven); // true

Ta metoda przydaje się do szybkiego sprawdzenia, czy co najmniej jeden element kolekcji spełnia określony warunek, na przykład czy kolekcja zawiera co najmniej jedną liczbę parzystą.

Zobacz every().

toIterator(iterable $iterable): Iterator

Konwertuje dowolny obiekt iterowalny (tablicę, Traversable) na Iterator. Jeśli wejściem jest już Iterator, zwracany jest bez zmian.

$array = [1, 2, 3];
$iterator = Iterables::toIterator($array);
// teraz masz Iterator zamiast tablicy

Ta metoda przydaje się, gdy potrzebujesz mieć pewność, że dysponujesz Iteratorem, niezależnie od typu danych wejściowych. Bywa to pomocne przy tworzeniu funkcji pracujących z różnymi typami danych iterowalnych.