Arbeiten mit Iteratoren
Nette\Utils\Iterables ist eine statische Klasse mit Funktionen für die Arbeit mit Iteratoren. Ihr Gegenstück für Arrays ist Nette\Utils\Arrays.
Installation:
composer require nette/utils
Alle Beispiele setzen voraus, dass dieser Alias angelegt wurde:
use Nette\Utils\Iterables;
contains (iterable $iterable, $value): bool
Sucht einen angegebenen Wert in einem Iterator. Für die Prüfung auf Übereinstimmung wird ein strikter Vergleich
(===) verwendet. Gibt true zurück, wenn der Wert gefunden wird, sonst false.
Iterables::contains(new ArrayIterator([1, 2, 3]), 1); // true
Iterables::contains(new ArrayIterator([1, 2, 3]), '1'); // false
Diese Methode ist nützlich, wenn Sie schnell feststellen müssen, ob ein bestimmter Wert in einem Iterator vorkommt, ohne alle Elemente von Hand zu durchlaufen.
containsKey (iterable $iterable, $key): bool
Sucht einen angegebenen Schlüssel in einem Iterator. Für die Prüfung auf Übereinstimmung wird ein strikter Vergleich
(===) verwendet. Gibt true zurück, wenn der Schlüssel gefunden wird, sonst 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
Prüft, ob alle Elemente des Iterators die in $predicate definierte Bedingung erfüllen. Der Callback
$predicate hat die Signatur function ($value, $key, iterable $iterable): bool und muss für jedes
Element true zurückgeben, damit die Methode every() true zurückgibt.
$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isBelowThreshold = fn($value) => $value < 40;
$res = Iterables::every($iterator, $isBelowThreshold); // true
Diese Methode ist nützlich, um zu prüfen, ob alle Elemente einer Sammlung eine bestimmte Bedingung erfüllen, etwa ob alle Zahlen kleiner als ein bestimmter Wert sind.
filter (iterable $iterable, callable $predicate): Generator
Erzeugt einen neuen Iterator, der nur die Elemente des ursprünglichen Iterators enthält, die die in $predicate
definierte Bedingung erfüllen. Der Callback $predicate hat die Signatur
function ($value, $key, iterable $iterable): bool und muss für die Elemente true zurückgeben, die
erhalten bleiben sollen.
$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::filter($iterator, fn($v) => $v < 3);
// 1, 2
Die Methode verwendet einen Generator, das Filtern geschieht also nach und nach, während Sie das Ergebnis durchlaufen. Das ist speicherschonend und erlaubt die Verarbeitung sehr großer Sammlungen. Wenn Sie nicht alle Elemente des resultierenden Iterators durchlaufen, sparen Sie Rechenleistung, weil nicht alle Elemente des ursprünglichen Iterators verarbeitet werden.
first (iterable $iterable, ?callable $predicate=null, ?callable $else=null): mixed
Gibt das erste Element des Iterators zurück. Ist $predicate angegeben, gibt sie das erste Element zurück, das
die Bedingung erfüllt. Der Callback $predicate hat die Signatur
function ($value, $key, iterable $iterable): bool. Wird kein passendes Element gefunden, wird der Callback
$else aufgerufen (sofern angegeben) und sein Ergebnis zurückgegeben. Ist $else nicht angegeben, wird
null zurückgegeben.
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
Diese Methode ist nützlich, wenn Sie schnell das erste Element einer Sammlung oder das erste Element mit einer bestimmten Eigenschaft brauchen, ohne die gesamte Sammlung von Hand zu durchlaufen.
firstKey (iterable $iterable, ?callable $predicate=null, ?callable $else=null): mixed
Gibt den Schlüssel des ersten Elements des Iterators zurück. Ist $predicate angegeben, gibt sie den Schlüssel
des ersten Elements zurück, das die Bedingung erfüllt. Der Callback $predicate hat die Signatur
function ($value, $key, iterable $iterable): bool. Wird kein passendes Element gefunden, wird der Callback
$else aufgerufen (sofern angegeben) und sein Ergebnis zurückgegeben. Ist $else nicht angegeben, wird
null zurückgegeben.
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
Erzeugt einen neuen Iterator, indem der Callback $transformer auf jedes Element des ursprünglichen Iterators
angewendet wird. Der Callback $transformer hat die Signatur
function ($value, $key, iterable $iterable): mixed, und sein Rückgabewert dient als neuer Wert des Elements.
$iterator = new ArrayIterator([1, 2, 3]);
$iterator = Iterables::map($iterator, fn($v) => $v * 2);
// 2, 4, 6
Die Methode verwendet einen Generator, die Transformation geschieht also nach und nach, während Sie das Ergebnis durchlaufen. Das ist speicherschonend und erlaubt die Verarbeitung sehr großer Sammlungen. Wenn Sie nicht alle Elemente des resultierenden Iterators durchlaufen, sparen Sie Rechenleistung, weil nicht alle Elemente des ursprünglichen Iterators verarbeitet werden.
mapWithKeys (iterable $iterable, callable $transformer): Generator
Erzeugt einen neuen Iterator, indem die Werte und Schlüssel des ursprünglichen Iterators transformiert werden. Der Callback
$transformer hat die Signatur function ($value, $key, iterable $iterable): ?array{$newKey, $newValue}.
Gibt $transformer den Wert null zurück, wird das Element übersprungen. Bei den behaltenen Elementen
dient das erste Element des zurückgegebenen Arrays als neuer Schlüssel und das zweite als neuer Wert.
$iterator = new ArrayIterator(['a' => 1, 'b' => 2]);
$iterator = Iterables::mapWithKeys($iterator, fn($v, $k) => $v > 1 ? [$v * 2, strtoupper($k)] : null);
// [4 => 'B']
Wie map() verwendet auch diese Methode einen Generator, verarbeitet also nach und nach und schont den Speicher. So
lässt sich mit großen Sammlungen arbeiten und Rechenleistung sparen, wenn Sie das Ergebnis nur teilweise durchlaufen.
memoize (iterable $iterable): IteratorAggregate
Erzeugt einen Wrapper um einen Iterator, der dessen Schlüssel und Werte während des Durchlaufs zwischenspeichert. Das erlaubt es, die Daten mehrfach zu durchlaufen, ohne die ursprüngliche Datenquelle erneut zu durchlaufen.
$iterator = /* ... */; // Daten, die sich nicht mehrfach durchlaufen lassen
$memoized = Iterables::memoize($iterator);
// Jetzt lässt sich $memoized mehrfach durchlaufen, ohne Daten zu verlieren
Diese Methode ist in Situationen nützlich, in denen Sie dieselbe Datenmenge mehrfach durchlaufen müssen, der ursprüngliche Iterator aber kein wiederholtes Durchlaufen erlaubt oder ein erneuter Durchlauf teuer wäre (etwa beim Lesen von Daten aus einer Datenbank oder Datei).
repeatable (callable $factory): IteratorAggregate
Erlaubt das wiederholte Durchlaufen von Objekten, die das sonst nicht unterstützen, typischerweise von PHP-Generatoren. Die Methode repeatable()
löst dieses Problem elegant: Statt des Iterators selbst übergeben Sie eine Funktion, die ihn erzeugt. Diese Factory wird dann
bei jedem Durchlauf automatisch aufgerufen.
// Ein üblicher Generator, der sich nicht zweimal durchlaufen lässt
$generator = function () {
yield 'A';
yield 'B';
};
$iterator = Iterables::repeatable($generator);
foreach ($iterator as $v) echo $v; // Gibt aus: AB
foreach ($iterator as $v) echo $v; // Gibt aus: AB (der Generator lief erneut)
Diese Methode ist eine Alternative zu memoize() in Situationen, in denen Sie mit großen
Datenmengen arbeiten, denn repeatable() speichert die Daten nicht zwischen, sondern erzeugt sie bei jedem
Durchlauf neu.
some (iterable $iterable, callable $predicate): bool
Prüft, ob mindestens ein Element des Iterators die in $predicate definierte Bedingung erfüllt. Der Callback
$predicate hat die Signatur function ($value, $key, iterable $iterable): bool und muss für mindestens
ein Element true zurückgeben, damit die Methode some() true zurückgibt.
$iterator = new ArrayIterator([1, 30, 39, 29, 10, 13]);
$isEven = fn($value) => $value % 2 === 0;
$res = Iterables::some($iterator, $isEven); // true
Diese Methode ist nützlich, um schnell zu prüfen, ob mindestens ein Element einer Sammlung eine bestimmte Bedingung erfüllt, etwa ob die Sammlung mindestens eine gerade Zahl enthält.
Siehe every().
toIterator (iterable $iterable): Iterator
Wandelt ein beliebiges iterierbares Objekt (Array, Traversable) in einen Iterator um. Ist die Eingabe bereits ein Iterator, wird sie unverändert zurückgegeben.
$array = [1, 2, 3];
$iterator = Iterables::toIterator($array);
// Jetzt haben Sie statt eines Arrays einen Iterator
Diese Methode ist nützlich, wenn Sie sicherstellen müssen, dass Ihnen ein Iterator zur Verfügung steht, unabhängig vom Typ der Eingabedaten. Das kann beim Schreiben von Funktionen helfen, die mit verschiedenen Arten iterierbarer Daten arbeiten.