snoot: Mehrdimensionales Array durchsuchen - nur über Schleife?

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.

  1. 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";

    1. 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

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. 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";

        1. 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

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. 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";

            1. 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

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. Hello,

                habe mal so zum Spaß einen Lösungsansatz dafür erzeugt:

                <?php  ### find_deep_key.php ###

                einen Arraykey finden für einen Wert, der in einem verzweigten Array versteckt ist

                $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

                --
                Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
                1. 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

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
              2. 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";

    2. 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!?

      1. 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";

  2. 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.

    1. 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 :)