Array rekursiv durchsuchen - die Dritte
Maik W. aus E.
- php
Tach zusammen,
ich war hier und hier schonmal mit dem Thema da, offensichtlich ist zur Zeit so viel los, daß der Schwanzabschneider immer schneller ist als ich...
Trotzdem ich brav alle Ratschläge befolgt und jede Menge Zeit in Fehlerjagd investiert habe, klappt es immer noch nicht mit meiner Funktion. Das habe ich bisher:
function mwe_search($haystack, $needle, $searchKey = null, $path = '', $sep = '/'){
foreach($haystack as $key =>$value){
if (is_array($value)) {
$path .= $sep. $value['href'];
return mwe_search($value,$needle, $searchKey, $path);
}else{//ist kein Array
if(!$searchKey == null){
if($searchKey == $key){
if($value == $needle){
return $path;
}else{//value gleich needle zu
return false;
}
}else{//wenn searchkey gleich key
if($value == $needle) {
return $path;
}else{
return false;
}
}
}//if not searchkey zu
}//else isarray zu
}//foreach zu
}//funktion zu
Alle Kontrollausgaben zeigen mir, daß es offenbar schon mit dem 'is_array' zur Unterscheidung hakt, und der Pfadaufbau nicht stimmt, denn für jedes foreach hängt er alle $value['href'] - Werte aneinander...
Ich bin echt ratlos, das geht offensichtlich über meinen Horizont;
also dedlfix, wenn Du das hier liest, melde Dich doch bitte bei mir, ich hab' da einen Auftrag...
Maik
Hey Maik,
ich weis leider nicht genau wie das in PHP ist aber in JAVA werden Funktionen ohne "return" aufgerufen. return gibt meiner Meinung nach nur einen Wert zurück. Versuch das ganze doch mal so
function mwe_search($haystack, $needle, $searchKey = null, $path = '', $sep = '/'){
foreach($haystack as $key =>$value){
if (is_array($value)) {
$path .= $sep. $value['href'];
mwe_search($value,$needle, $searchKey, $path);
}else{//ist kein Array
if(!$searchKey == null){
if($searchKey == $key){
if($value == $needle){
return $path;
}else{//value gleich needle zu
return false;
}
}else{//wenn searchkey gleich key
if($value == $needle) {
return $path;
}else{
return false;
}
}
}//if not searchkey zu
}//else isarray zu
}//foreach zu
}//funktion zu
Viele Grüße
Jan
Moin!
ich weis leider nicht genau wie das in PHP ist aber in JAVA werden Funktionen ohne "return" aufgerufen. return gibt meiner Meinung nach nur einen Wert zurück.
Auch in PHP werden Funktionen nicht mit return aufgerufen.
Aber bei rekursiven Funktionen kann man die Funktion aufrufen, und deren Ergebnis direkt zurückgeben.
Versuch das ganze doch mal so
Das zerstört die Rekursivität. Das Funktionsergebnis wird nirgends mehr gespeichert und zurückgegeben.
- Sven Rautenberg
Tach auch Sven,
Aber bei rekursiven Funktionen kann man die Funktion aufrufen, und deren Ergebnis direkt zurückgeben.
Genau das möchte ich tun. Ich brauche auch nur das Ergebnis, sobald ich es habe, soll die Funktion abgebrochen werden. Schwierig ist es für mich, weil eben noch arrays im array sein können und ich eben den href-Wert der ersten und zweiten "Ebene" brauche.
Maik
Moin!
ich weis leider nicht genau wie das in PHP ist aber in JAVA werden Funktionen ohne "return" aufgerufen. return gibt meiner Meinung nach nur einen Wert zurück.
Auch in PHP werden Funktionen nicht mit return aufgerufen.
Aber bei rekursiven Funktionen kann man die Funktion aufrufen, und deren Ergebnis direkt zurückgeben.
Versuch das ganze doch mal so
Das zerstört die Rekursivität. Das Funktionsergebnis wird nirgends mehr gespeichert und zurückgegeben.
- Sven Rautenberg
Achso naja das wusste ich nicht. In Java wird ja auch immer festgelegt ob ein Wiedergabewert Existiert oder nicht (mit public String lala() würde meine Funktion lala() einen String zurückgeben. Mit public void lala() halt nix). Und da hast du recht wenn ich nen Wiedergabewert habe rufe ich die Funktion auch mit return auf.
Viele Grüße
Jan
hi,
bitte zitiere sinnvoll, danke.
Achso naja das wusste ich nicht. In Java wird ja auch immer festgelegt ob ein Wiedergabewert Existiert oder nicht (mit public String lala() würde meine Funktion lala() einen String zurückgeben. Mit public void lala() halt nix). Und da hast du recht wenn ich nen Wiedergabewert habe rufe ich die Funktion auch mit return auf.
Da besteht immer noch kein Zusammenhang.
Es geht nicht darum, _ob_ die Funktion einen Rückgabewert hat, sondern _was_ mit diesem gemacht wird.
Und im Beispiel wird er mittels return aus der aktuellen Rekursionsebene an die nächsthöhere zurückgegeben.
gruß,
wahsaga
echo $begrüßung;
Alle Kontrollausgaben zeigen mir, daß es offenbar schon mit dem 'is_array' zur Unterscheidung hakt, und der Pfadaufbau nicht stimmt, denn für jedes foreach hängt er alle $value['href'] - Werte aneinander...
Ich bin echt ratlos, das geht offensichtlich über meinen Horizont;
Du hast also von meinem Vorschlag die Variante b versucht umzusetzen. Dabei verlässt du die Funktion zu schnell. Sie darf nur dann ein false liefern, wenn das Array ergebnislos durchlaufen wurde. Deine Version läuft auf ein return false; sobald der Vergleich misslang. Die weiteren Array-Elemente kommen nun nicht mehr zum Zug.
Außerdem darfst du $path nicht verändern, sondern nur einen String übergeben, der aus seinem Inhalt plus dem neuen Pfad-Teil besteht.
Hier mal meine Version:
function mwe_search($haystack, $needle, $searchKey = null, $path = '', $sep = '/'){
foreach($haystack as $key =>$value) {
if (is_array($value)) {
if ($result = mwe_search($value,$needle, $searchKey, $path . $sep . $value['href'])) // Zuweisung, kein Vergleich
return $result;
} else {
if ($searchKey !== null) {
if (($searchKey == $key) and ($value == $needle))
return $path;
} elseif ($value == $needle)
return $path;
} //else isarray zu
} //foreach zu
return false;
} //funktion zu
echo "$verabschiedung $name";
Tach auch dedlfix,
Du hast also von meinem Vorschlag die Variante b versucht umzusetzen. Dabei verlässt du die Funktion zu schnell. Sie darf nur dann ein false liefern, wenn das Array ergebnislos durchlaufen wurde. Deine Version läuft auf ein return false; sobald der Vergleich misslang. Die weiteren Array-Elemente kommen nun nicht mehr zum Zug.
Deswegen...
Außerdem darfst du $path nicht verändern, sondern nur einen String übergeben, der aus seinem Inhalt plus dem neuen Pfad-Teil besteht.
Hier mal meine Version:
function mwe_search($haystack, $needle, $searchKey = null, $path = '', $sep = '/'){
foreach($haystack as $key =>$value) {
if (is_array($value)) {
if ($result = mwe_search($value,$needle, $searchKey, $path . $sep . $value['href'])) // Zuweisung, kein Vergleich
return $result;
} else {
if ($searchKey !== null) {
if (($searchKey == $key) and ($value == $needle))
return $path;
} elseif ($value == $needle)
return $path;
} //else isarray zu
} //foreach zureturn false;
} //funktion zu
Perfekt! Das ist es! Genau so muß es funktionieren! Herzlichen Dank, mir fällt ein echter Brocken vom Herzen; Du hast nicht zufällig eine Amazon-Wunschliste?
Danke und
<http://www.gruss-aus-essen.de>
Maik
--
![Diese Dauerleihgabe wird Ihnen präsentiert von ROMY!](http://www.gruss-aus-essen.de/selfforum/totes_huhn.jpg)
Maik. W. aus E. sagt Dankeschön ;-)
Tach.
Laß uns die ganze Sache einfach mal schrittweise entwickeln:
Bisher hast du nicht definiert, welche Form genau dein "Pfad" haben soll. Wenn es jeweils der Inhalt von "href" sein soll, kriegst du Probleme mit der oberstern Ebene in deinem Array $entries -- dort existiert nämlich kein Schlüssel "href". Wie soll z. B. das Ergebnis deiner Suche nach "nachrichten" in deinem Beispielarray aussehen?
Umgehen könntest du dieses Problem, indem du $entries einen zusätzlichen Eintrag "href" spendierst, der auch leer sein kann (als root sozusagen). Ob und wie du deine Struktur änderst, bleibt natürlich dir überlassen. Ich würde dir ebenfalls eine Umstrukturierung ans Herz legen, wie sie wahsaga bereits vorschlug. Damit sparst du dir auch bei künftigen Erweiterungen einigen Ärger.
Nun gut ... Ich wähle als Bestandteile der Pfadangabe jetzt einfach mal den (numerischen) Schlüssel des Arrays, da das eindeutig den Weg durch deine Datenstruktur beschreibt. Wenn dir das nicht gefällt, mußt du die Funktion entsprechend abändern.
Genug der Vorrede.
Die Funktion search() soll in einem verschachtelten Array $haystack alle Felder mit Schlüssel $searchKey nach dem Wert $needle durchsuchen. Die Suche bricht nach dem ersten Treffer ab. Als Ergebnis gibt sie einen String zurück, in dem mit Arrayindizes der Pfad zum zutreffenden Element angegeben ist. Die Indizes werden durch ein festgelegte Zeichen $separator voneinander getrennt. Wird nichts gefunden, bleibt der Rückgabestring leer. Dazu folgendes Grundgerüst:
function search ($haystack, $needle, $searchKey = "href", $separator = "/") {
if (!is_array($haystack)) {
return "";
}
foreach ($haystack as $key => $val) {
// Inhalt des aktuellen Feldes mit dem Suchbegriff vergleichen
if ($key === $searchKey) {
// ...
}
// Kindelemente nach $needle durchsuchen
else if (is_array($val)) {
// ...
}
// andere Felder
else {
// ...
}
}
return "";
}
Die Fallunterscheidung liefert als erste Möglichkeit einen Schlüssel, der genau dem zu überprüfenden $searchKey entspricht -- bei dir ist das "href". In diesem Fall müssen wir nur überprüfen, ob der zugehörige Wert auch mit $needle übereinstimmt. Falls ja, können wir die Suche beenden und als Ergebnis den Pfad durch das Array zurückgeben, der zum aktuellen Feld führt.
// Inhalt des aktuellen Feldes mit dem Suchbegriff vergleichen
if ($key === $searchKey) {
if ($val == $needle) {
// $needle im aktuellen Feld gefunden! Suche beenden.
return $separator . $key;
}
}
Als nächster Fall kann ein Feld auftreten, das selber ein Array ist und die Kindelemente des Feldes auf der aktuellen Ebene darstellt. Da wir gerade schon eine Funktion schreiben, die ein verschachteltes Array nach $needle durchsucht, können wir sie einfach auf dieses Array anwenden. ;) Wie oben festgelegt, bleibt der Rückgabewert ein leerer String, falls in dem Array kein passender Wert gefunden wurde. In diesem Fall heißt es "weitersuchen". Ist der Pfad aber nicht leer, wurde in den Kindern etwas gefunden und wir können die Suche abbrechen.
// Kindelemente nach $needle durchsuchen
else if (is_array($val)) {
$path = search($val, $needle, $searchKey, $separator);
// $needle in einem der Kinder gefunden! Suche beenden.
if ($path != "") {
return $separator . $key . $path;
}
}
Alle restlichen Ergebnisse der Fallunterscheidung interessieren uns nicht weiter. In diese Kategorie fallen z. B. die Schlüssel "text" und "title". Der letzte else-Zweig kann also leer bleiben oder gleich ganz gestrichen werden.
Insgesamt sieht das dann so aus:
function search ($haystack, $needle, $searchKey = "href", $separator = "/") {
if (!is_array($haystack)) {
return "";
}
foreach ($haystack as $key => $val) {
// Inhalt des aktuellen Feldes mit dem Suchbegriff vergleichen
if ($key === $searchKey) {
if ($val == $needle) {
// $needle im aktuellen Feld gefunden! Suche beenden.
return $separator . $key;
}
}
// Kindelemente nach $needle durchsuchen
else if (is_array($val)) {
$path = search($val, $needle, $searchKey, $separator);
// $needle in einem der Kinder gefunden! Suche beenden.
if ($path != "") {
return $separator . $key . $path;
}
}
}
return "";
}
Auf dein Beispielarray angewandt erhalten wir z. B. folgende Ergebnisse:
search($entries, "nachrichten"); // "/0/href"
search($entries, "nüscht"); // ""
search($entries, "archiv"); // "/3/2/href"
Sei dir aber bitte der Tatsache bewußt, daß das eine ziemlich wacklige Angelegenheit werden kann. Die ganze Sache geht z. B. nach hinten los, wenn du aus irgendwelchen Gründen in Felder mit dem Schlüssel "href" ein Array steckst. Überleg dir einfach nochmal, ob es sich nicht doch lohnt, das ganze in einer vernünftigen Klasse zu kapseln, die auch das Erstellen deiner Navigationsstruktur unanfälliger gegen Falscheingaben machen kann!