Mehrdimensionales Array durchsuchen - nur über Schleife?
snoot
- php
Hi,
ich habe zwei mehrdimensionales Arrays, die ich durchsuchen will. Ist das wirklich nur möglich, in dem ich das Array mit einer bzw. zwei Schleife durchlaufe?
Ich will wissen, ob $_GET['thema'] in den Arrays existiert. Im Moment mache ich das so, dass ich eine Variable auf 1 setze und diese 0 gesetzt wird, wenn in der Schleife der entsprechende Wert gefunden wird.
$fehler_thema = 1;
if(isset($_GET['thema']))
{
foreach($index as $topic => $chapters)
{
foreach($chapters as $chapter => $none)
{
if($_GET['thema'] == $chapter)
{
$fehler_thema = 0;
}
}
}
}
if(isset($_GET['thema']) && $fehler_thema == 1)
{
... Abbruch ...
}
Ich habe schon gegooglet und als Alternative Funktionen in dieser Art gefunden:
function get_array_key($search, $array)
{
foreach($array as $key => $values)
{
if(in_array($search, $values))
{
return $key;
}
}
return false;
}
$key = get_array_key('gesuchter_wert', $mehrdimensionales_array);
Das wäre ein wenig kürzer, liefert mir aber gar nichts zurück.
echo $begrüßung;
ich habe zwei mehrdimensionales Arrays, die ich durchsuchen will. Ist das wirklich nur möglich, in dem ich das Array mit einer bzw. zwei Schleife durchlaufe?
PHP bietet keine Möglichkeit, in verschachtelten Arrays zu suchen. Der Anwendungsfall "Der Wert ist irgendwo da drin" ist nicht sehr häufig. Und wenn man die Fundstelle haben möchte, was soll man dann zurückgeben? Einen Verweis auf den einen Wert? Irgendwie den Pfad der dorthin führt? Wie soll das konkret aussehen? Und wollen mindestens 80% aller Anwender das genauso haben, damit sich eine Implementation lohnt?
Ich will wissen, ob $_GET['thema'] in den Arrays existiert. Im Moment mache ich das so, dass ich eine Variable auf 1 setze und diese 0 gesetzt wird, wenn in der Schleife der entsprechende Wert gefunden wird.
Und wenn der Wert gefunden wurde kannst du abbrechen.
Ich habe schon gegooglet und als Alternative Funktionen in dieser Art gefunden:
Das wäre ein wenig kürzer, liefert mir aber gar nichts zurück.
Da fehlt die Rekursivität. So läufst du nur durch das äußere Array, was du mit Kontrollausgaben gesehen hättest.
echo "$verabschiedung $name";
Hello,
Und wenn der Wert gefunden wurde kannst du abbrechen.
in einem verzweigten (nicht verschachtelt!) Array (=Baumstruktur) kann der Wert auch mehrfach versteckt sein! Man müsste dann also jeden Key(-Pfad ) ermitteln, der zum Vorkommen führt.
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
echo $begrüßung;
» Und wenn der Wert gefunden wurde kannst du abbrechen.
in einem verzweigten (nicht verschachtelt!) Array (=Baumstruktur) kann der Wert auch mehrfach versteckt sein! Man müsste dann also jeden Key(-Pfad ) ermitteln, der zum Vorkommen führt.
Nur wenn man die Keys (oder Pfade zu den Elementen) haben möchte, was aber hier nicht gefordert war.
echo "$verabschiedung $name";
Hello,
» Und wenn der Wert gefunden wurde kannst du abbrechen.
in einem verzweigten (nicht verschachtelt!) Array (=Baumstruktur) kann der Wert auch mehrfach versteckt sein! Man müsste dann also jeden Key(-Pfad ) ermitteln, der zum Vorkommen führt.Nur wenn man die Keys (oder Pfade zu den Elementen) haben möchte, was aber hier nicht gefordert war.
Also wollte snoot nur wissen, ob der Wert überhaupt in dem verzweigten Array vorhanden ist?
Das habe ich überlesen. Mir dünkte, dass man meistens auch wissen möchte, wo der steckt :-)
Und dann ist es tatsächlich nicht mehr ganz so einfach, _wie_ man denn überhaupt den Pfad zu diesem Wert zurückgibt. Wie würdest Du das machen?
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
echo $begrüßung;
Mir dünkte, dass man meistens auch wissen möchte, wo der steckt :-)
Ja, deshalb schweifte ich in meiner ersten Antwort auch in diese Richtung ab.
Und dann ist es tatsächlich nicht mehr ganz so einfach, _wie_ man denn überhaupt den Pfad zu diesem Wert zurückgibt. Wie würdest Du das machen?
Da ich ebenso wenig ein Patentrezept habe wie anscheinend die PHP-Programmierer auch: Kommt drauf an, was gefordert ist. Ich würde sicherlich zu vermeiden versuchen, eine solche Struktur erst aufzubauen und dann darin zu suchen. Irgendwo kommen die Daten her und sind dort (hoffentlich) besser durchsuchbar.
echo "$verabschiedung $name";
Hello,
Da ich ebenso wenig ein Patentrezept habe wie anscheinend die PHP-Programmierer auch: Kommt drauf an, was gefordert ist. Ich würde sicherlich zu vermeiden versuchen, eine solche Struktur erst aufzubauen und dann darin zu suchen. Irgendwo kommen die Daten her und sind dort (hoffentlich) besser durchsuchbar.
Irgedwie fällt mir nicht ein, wie man das machen könnte. Man kann zwar das Literal des Deep-Keys aufbauen, aber ohne eval() wird man es wohl später nicht benutzen können. Da fehlt mir einfach die Idee.
Bleibt also nur je eine Referenz auf die Treffer?
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
Hello,
habe mal so zum Spaß einen Lösungsansatz dafür erzeugt:
<?php ### find_deep_key.php ###
$needle = 'treffer';
$_haystack = array();
$_haystack['first'] = array();
$_haystack['second'] = array();
$_haystack['third'] = array();
$_haystack['forth'] = $needle;
$_haystack['fifth'] = array();
$_haystack['first']['eins'] = 'leider';
$_haystack['first']['zwei'] = 'kein';
$_haystack['first'][3] = 'treffer';
$_haystack['second'][0] = array();
$_haystack['second'][1] = $needle;
echo "<pre>\r\n";
echo htmlspecialchars(print_r($_haystack,1));
echo "</pre>\r\n";
#-----------------------------------------------------------
function find_hits($_haystack, $needle, &$_hits, $keyrank)
{
foreach($_haystack as $key => $value)
{
if (is_array($value))
{
find_hits($value, $needle, $_hits, $keyrank."[$key]");
}
elseif ($value == $needle)
{
$_hits[] = $keyrank."[$key]";
}
}
}
#-----------------------------------------------------------
$_hits = array();
$keyrank = '';
$keyrank = '$_haystack';
find_hits($_haystack, $needle, $_hits, $keyrank);
echo "<pre>\r\n";
echo htmlspecialchars(print_r($_hits,1));
echo "</pre>\r\n";
?>
Das ergibt dann:
Array
(
[first] => Array
(
[eins] => leider
[zwei] => kein
[3] => treffer
)
[second] => Array
(
[0] => Array
(
)
[1] => treffer
)
[third] => Array
(
)
[forth] => treffer
[fifth] => Array
(
)
)
Array
(
[0] => $_haystack[first][3]
[1] => $_haystack[second][1]
[2] => $_haystack[forth]
)
Ist natürlich nur eine Grundidee und noch optimierungsbedürftig.
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
Hello,
... wenn man damit weiterarbeiten will, könnte man alternativ auch die Arraystruktur, die Treffer enthält, nachbilden und extrahieren.
Das dürfte dann noch komplexer werden. Man müsste jeden Pfad erst schrittweise aufnehmen in das Ergebnisarray und auf dem Rückweg solange wieder löschen aus der Struktur, bis ein Treffer gefunden wurde.
Das ist eben die Krux zwischen serialisierter Pfadanzeige und rekursiver (indirekter) Referenzierung der Daten.
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
echo $begrüßung;
Irgedwie fällt mir nicht ein, wie man das machen könnte. Man kann zwar das Literal des Deep-Keys aufbauen, aber ohne eval() wird man es wohl später nicht benutzen können. Da fehlt mir einfach die Idee.
Bleibt also nur je eine Referenz auf die Treffer?
Wenn du wirklich keine grundlegende bessere Lösung für den konkreten Anwendungsfall findest, fallen mir noch zwei weitere Lösungen ein. Rekursiv den Wert finden oder bei überschaubarer Maximal-Schachtlungstiefe eine spezialisierte Funktion.
function find() {
if (func_num_args() > 2)
;// zu viel
if (func_num_args() == 2)
return $array[func_get_arg(0)][func_get_arg(1)];
if (func_num_args() == 1)
return $array[func_get_arg(0)];
return $array;
}
Die Sichtbarkeit von $array habe ich mal unbeachtet gelassen. Man könnte das als Parameter übergeben und müsste dann die Auswertung der Argumenteanzahl anpassen. Oder eine Klasse um das Problem stricken.
echo "$verabschiedung $name";
Und wenn man die Fundstelle haben möchte, was soll man dann zurückgeben?
true von mir aus :)
Und wenn der Wert gefunden wurde kannst du abbrechen.
Aja, mit break 2;
in der if-Anweisung!?
echo $begrüßung;
» Und wenn man die Fundstelle haben möchte, was soll man dann zurückgeben?
true von mir aus :)
Ja, für deinen speziellen Fall. Doch manchmal will man wissen, wo der Wert steckt und da reicht nicht einfach nur ein true/false.
» Und wenn der Wert gefunden wurde kannst du abbrechen.
Aja, mit break 2; in der if-Anweisung!?
Ja, das bricht beide Schleifen ab.
echo "$verabschiedung $name";
Hi snoot,
$fehler_thema = 1;
if(isset($_GET['thema']))
{
foreach($index as $topic => $chapters)
{
foreach($chapters as $chapter => $none)
{
if($_GET['thema'] == $chapter)
{
$fehler_thema = 0;
}
}
}
}
Wie man dir bereits gesagt hat, kommst du nicht drum rum das Array zu durchlaufen. Da du allerdings einen Key suchst (und keinen Wert), kannst du dir die innere foreach-Schleife sparen:
[ode lang=php]if (isset($\_GET['thema'])) {
foreach ($index as $topic => $chapters) {
if (isset($chapters[$\_GET['thema']])) {
$fehler\_thema = 0;
break;
}
}
}[/code]
Mit break brichst du dann noch direkt ab, wenn du das passende Unter-Array gefunden hast.
Alternativer Ansatz:
~~~php
$fullIndex = call_user_func_array('array_merge', $index);
if (isset($fullIndex[$_GET['thema']])) {
$fehler_thema = 0;
}
Viele Grüße,
~ Dennis.
Wie man dir bereits gesagt hat, kommst du nicht drum rum das Array zu durchlaufen. Da du allerdings einen Key suchst (und keinen Wert), kannst du dir die innere foreach-Schleife sparen:
Danke, das sieht doch ein wenig besser/performanter aus :)