Ich habe eine Klasse namens Collection die Objekte des gleichen Typs speichert. Collection implementiert Array-Schnittstellen: Iterator, ArrayAccess, SeekableIteratorund Countable.
Ich möchte a bestehen Collection Objekt als Array-Argument für die array_map Funktion. Dies schlägt aber mit dem Fehler fehl
PHP-Warnung: array_map(): Argument #2 sollte ein Array sein
Kann ich dies erreichen, indem ich andere/mehrere Schnittstellen implementiere, so dass Collection Objekte werden als Arrays gesehen?
Erstellen Sie Ihre eigene collection_map-Funktion?
– Addierer
29. April 2013 um 8:21 Uhr
@Adder Natürlich kann ich, aber jetzt suche ich nach einer Lösung, wenn ich meine Sammlung mit eingebauten PHP-Funktionen verwenden kann 🙂
– Flammen
29. April 2013 um 8:28 Uhr
Jack
Das array_map() Funktion unterstützt nicht a Traversable als sein Array-Argument, also müssten Sie einen Konvertierungsschritt durchführen:
array_map($fn, iterator_to_array($myCollection));
Neben der zweimaligen Iteration über die Sammlung ergibt sich auch ein Array, das danach nicht mehr verwendet wird.
Eine andere Möglichkeit besteht darin, eine eigene Kartenfunktion zu schreiben:
function map(callable $fn)
{
$result = array();
foreach ($this as $item) {
$result[] = $fn($item);
}
return $result;
}
Aktualisieren
Nach Ihrem Anwendungsfall zu urteilen, scheinen Sie nicht einmal am Ergebnis der Kartenoperation interessiert zu sein. daher ist es sinnvoller zu verwenden iterator_apply().
Dies funktioniert, hat aber eine Leistungseinbuße, da es während des iterator_to_array-Schritts iteriert und während des array_map-Schritts erneut iteriert wird.
– Eelke van den Bos
30. Januar 2014 um 18:15 Uhr
@EelkevandenBos Ich habe in meiner Antwort zwei Lösungen gegeben, wobei letztere diese “Leistungseinbuße” nicht aufweist; außerdem ist die Laufzeit in beiden Fällen O(n).
– Jack
30. Januar 2014 um 23:26 Uhr
Ich denke, der Rückruf an iterator_apply erhält nicht die aktuelle Instanz als Argument. Aus den Dokumenten: “Diese Funktion empfängt nur die angegebenen Argumente, daher ist sie standardmäßig null.” Das Beispiel in der Dokumentation löst dies, indem der Iterator selbst als Argument übergeben und $iterator->current() verwendet wird. Dokumente: php.net/iterator_apply
– Ole
23. Mai 2019 um 11:18 Uhr
@Ole danke dafür, es könnte ein Versehen gewesen sein, als ich mein Update verfasst habe
– Jack
23. Mai 2019 um 12:55 Uhr
verzeihen
array_map möchte, wie der Name schon sagt, Arrays. Es heißt nicht iterator_map schließlich. 😉
Außer, abgesondert, ausgenommen iterator_to_array()die ein potenziell großes temporäres Array erzeugt, gibt es keinen Trick, um iterierbare Objekte zum Laufen zu bringen array_map.
Das Funktionales PHP Bibliothek hat eine map Implementierung, die auf jeder iterierbaren Sammlung funktioniert.
Die funktionale PHP-Map-Implementierung ist nicht speichereffizient: Die Ergebnisse werden in einem Array gespeichert. Ich habe eine bessere Bibliothek gefunden: github.com/SuRaMoN/itertools Und ein Blogbeitrag, der erklärt, wie Sie es selbst bauen können: a-basketful-of-papayas.net/2012/07/…
– Aad Mathijssen
27. Juli 2015 um 16:33 Uhr
Aad, im Allgemeinen ist das Ergebnis einer Kartenfunktion a Neu array – der Speicher-Overhead ist dem Ansatz inhärent und in den allermeisten Anwendungsfällen vernachlässigbar.
– Markus Fuchs
1. November 2016 um 19:01 Uhr
„Es gibt keinen Trick, um iterierbare Objekte zum Laufen zu bringen array_map.” Dieser Trick ist iterator_to_array().
– Nathan Arthur
12. Mai 2017 um 16:13 Uhr
@MarkFox Wenn der Iterator eine große Sammlung großer Arrays oder Objekte liefert und das aufrufbare jedes davon in einem kleineren Array, Objekt oder Primitiv zusammenfassen soll, ist der Speicheraufwand des ersten Aufrufs iterator_to_array() kann erheblich sein.
– Damian Yerrick
10. November 2017 um 15:57 Uhr
Chris M
Wenn du bist nicht daran interessiert sind, ein neues Array zu erstellen, das eine Funktion ist, die dem ursprünglichen Array zugeordnet ist, könnten Sie einfach eine foreach-Schleife verwenden (weil Sie implementieren Iterator).
foreach($item in $myCollection) {
$item->method1();
$item->method2();
}
Wenn Sie tatsächlich eine Karte verwenden möchten, müssen Sie meiner Meinung nach Ihre eigene implementieren. Ich würde vorschlagen, es zu einer Methode für die Sammlung zu machen, zB:
$mutatedCollection = $myCollection->map(function($item) {
/* do some stuff to $item */
return $item;
});
Ich würde mich fragen, ob Sie wirklich verwenden möchten map oder meinst du wirklich nur foreach
Ich bin auf folgende Lösung gekommen:
//lets say you have this iterator
$iterator = new ArrayIterator(array(1, 2, 3));
//and want to append the callback output to the following variable
$out = [];
//use iterator to apply the callback to every element of the iterator
iterator_apply(
$iterator,
function($iterator, &$out) {
$current = $iterator->current();
$out[] = $current*2;
return true;
},
array($iterator, &$out) //arguments for the callback
);
print_r($out);
Auf diese Weise können Sie ein Array generieren, ohne zweimal zu iterieren, wie Sie es mit dem folgenden Ansatz tun würden:
Ich bin gerade über diese Frage gestolpert und habe es geschafft, die Sammlung in ein Array zu werfen, damit es funktioniert:
array_map($cb, (array) $collection);
Haftungsausschluss Für die ursprüngliche Frage ist dies möglicherweise keine geeignete Option, aber ich habe die Frage gefunden, als ich nach einer Lösung für ein Problem gesucht habe, das ich mit dieser Lösung gelöst habe. Ich würde empfehlen, eine benutzerdefinierte Iteratorkarte zu verwenden, wo dies möglich/machbar ist.
Eine andere Möglichkeit ist, so etwas zu tun:
foreach($collection as &$item) {
$item = $cb($item);
}
wodurch die zugrunde liegende Sammlung mutiert wird.
BEARBEITEN:
Es wurde darauf hingewiesen, dass das Casting in ein Array unerwünschte Nebeneffekte haben kann. Es wäre besser, Ihrer Sammlung eine Methode hinzuzufügen, um das Array vom Iterator zurückzugeben und dieses zu durchlaufen, oder andernfalls eine hinzuzufügen map -Methode, die einen Rückruf akzeptiert und eine Schleife auf dem zugrunde liegenden Iterator ausführt.
Das blinde Casting in ein Array hat das Potenzial für unangenehme Nebenwirkungen, da Sie möglicherweise andere Daten aus dem Objekt in dem durchlaufen, was iteriert wird, anstatt nur die Daten zu erhalten, die das Iteratorobjekt umschließt/navigiert.
– GuyPaddock
26. April 2019 um 15:27 Uhr
Ich stimme dem Prinzip zu, da das Objekt jedoch eine Sammlung ist, wurde angenommen, dass keine anderen Daten an das Objekt gebunden waren.
– Andreas Willis
27. April 2019 um 16:06 Uhr
Angesichts der in der ursprünglichen Frage implementierten Schnittstellen kann man davon ausgehen, dass das Casting in ein Array eine Array-Darstellung des Iterators zurückgeben würde. Ich habe meine Antwort jedoch bearbeitet, um Fälle zu berücksichtigen, in denen Personen versuchen, über Klassen zu iterieren, die das nicht implementieren Schnittstellen im OP
– Andreas Willis
27. April 2019 um 16:14 Uhr
Das blinde Casting in ein Array hat das Potenzial für unangenehme Nebenwirkungen, da Sie möglicherweise andere Daten aus dem Objekt in dem durchlaufen, was iteriert wird, anstatt nur die Daten zu erhalten, die das Iteratorobjekt umschließt/navigiert.
– GuyPaddock
26. April 2019 um 15:27 Uhr
Ich stimme dem Prinzip zu, da das Objekt jedoch eine Sammlung ist, wurde angenommen, dass keine anderen Daten an das Objekt gebunden waren.
– Andreas Willis
27. April 2019 um 16:06 Uhr
Angesichts der in der ursprünglichen Frage implementierten Schnittstellen kann man davon ausgehen, dass das Casting in ein Array eine Array-Darstellung des Iterators zurückgeben würde. Ich habe meine Antwort jedoch bearbeitet, um Fälle zu berücksichtigen, in denen Personen versuchen, über Klassen zu iterieren, die das nicht implementieren Schnittstellen im OP
– Andreas Willis
27. April 2019 um 16:14 Uhr
11448800cookie-checkarray_map auf Sammlung mit Array-Schnittstellen?yes
Erstellen Sie Ihre eigene collection_map-Funktion?
– Addierer
29. April 2013 um 8:21 Uhr
@Adder Natürlich kann ich, aber jetzt suche ich nach einer Lösung, wenn ich meine Sammlung mit eingebauten PHP-Funktionen verwenden kann 🙂
– Flammen
29. April 2013 um 8:28 Uhr