Robert Allerstorfer: Array-Elemente nicht variabel ansprechbar?

Hallo,

ich bin gerade auf ein problem in perl gestossen:

ich habe 2 arrays, sagen wir mal
@english = ("man", "woman");
@deutsch = ("Mann", "Frau");

Will ich das zweite element ansprechen, so ergibt
explizit $deutsch[1] die Frau.

Weiss ich aber die sprache nicht explizit, sondern nur in der variable
$language = "deutsch";

so müsste ich doch auch zur Frau über $$language[1] kommen, das will Perl aber nicht.
Solche mehrdimensionale variablenfelder konnte man in basic leicht anlegen, sowas muss doch auch in perl möglich sein, oder?

Danke für Lösungsvorschläge,
Robert

  1. Hallo Robert,

    so müsste ich doch auch zur Frau über $$language[1] kommen, das will Perl aber nicht.
    Solche mehrdimensionale variablenfelder konnte man in basic leicht anlegen, sowas muss doch auch in perl möglich sein, oder?

    Das geht in Perl leider nicht, aber ich frage mich, wo hier das Problem genau liegt. Wo wird denn die Sprache vom Benutzer festgelegt?

    MfG Mr. Pixel

  2. Hallo,

    ich bin gerade auf ein problem in perl gestossen:

    ich habe 2 arrays, sagen wir mal
    @english = ("man", "woman");
    @deutsch = ("Mann", "Frau");

    Will ich das zweite element ansprechen, so ergibt
    explizit $deutsch[1] die Frau.

    Weiss ich aber die sprache nicht explizit, sondern nur in der variable
    $language = "deutsch";

    so müsste ich doch auch zur Frau über $$language[1] kommen, das will Perl aber nicht.
    Solche mehrdimensionale variablenfelder konnte man in basic leicht anlegen, sowas muss doch auch in perl möglich sein, oder?

    Danke für Lösungsvorschläge,
    Robert

    Man kann mit Referenzen sicher einiges anfangen:
    @english = ("man", "woman");
    @deutsch = ("Mann", "Frau");

    $sprachen{'english'} = @english;
    $sprachen{'deutsch'} = @deutsch;

    $string = $sprachen{$language}->[1];

    Das erzeugen der Listen geht auch etwas direkter (beachte die eckigen Klammern):
    $sprachen{'english'} = ["man", "woman"];
    $sprachen{'deutsch'} = ["Mann", "Frau"];

    Jörk

  3. Tag!

    @english = ("man", "woman");
    @deutsch = ("Mann", "Frau");

    so müsste ich doch auch zur Frau über $$language[1] kommen, das will Perl aber nicht.

    Nein, denn mit $$variable referenzierst Du eine Referenz (was fuer ein Satz!). Was das bedeutet, siehst Du auf <../../tgcb.htm#a4>.

    Wenn Du willst, dass sich $language zu "deutsch" aufloest, musst Du schon eval() benutzen (was das genau macht, siehe perldoc). Das sieht dann so aus:
        $frau = eval("$" . $language . "[1]");

    Solche mehrdimensionale variablenfelder konnte man in basic leicht anlegen, sowas muss doch auch in perl möglich sein, oder?

    Mit mehrdimensionalen Arrays hat das obige eigentlich nichts zu tun. Aber sicher geht das in Perl, wenn ich jetzt auf Anhieb auch nicht genau weiss, wie. Joerk hat Dir bereits etwas aehnliches beschrieben, was in diesem Fall wohl besser geeignet ist als ein zweidimenionales Array.

    Calocybe

    1. hi!

      Mit mehrdimensionalen Arrays hat das obige eigentlich
      nichts zu tun. Aber sicher geht das in Perl, wenn ich jetzt
      auf Anhieb auch nicht genau weiss, wie. Joerk hat Dir
      bereits etwas aehnliches beschrieben, was in diesem Fall
      wohl besser geeignet ist als ein zweidimenionales Array.

      Was Jörk beschrieben hat, ist in Perl quasi ein zweidimensionales Array, genauer gesagt ein Hash (= assoziatives Array) von Arrays.

      bye, Frank!

      1. Moin Frank!

        Was Jörk beschrieben hat, ist in Perl quasi ein zweidimensionales Array, genauer gesagt ein Hash (= assoziatives Array) von Arrays.

        Ein Hash, ja. Auch wenn ein Hash auch als assoziatives Array bezeichnet wird, so mache ich persoenlich trotzdem einen elementaren Unterschied zwischen Hash und Array. In erster Linie ist ein Array sortiert - im Gegensatz zum Hash. Was Joerk beschrieben hat, wuerde ich am ehesten als ein struct mit zwei Elementen interpretieren (struct gibt es ja in Perl eigentlich nicht). In C wuerde man schreiben:

        typedef struct {
            char ** english;
            char ** deutsch;
        } sprachen_struct;

        int main() {
            sprachen_struct sprachen;
            static char * english[] = {"man", "woman"};
            static char * deutsch[] = {"Mann", "Frau"};

        sprachen.english = english;
            sprachen.deutsch = deutsch;

        printf("english: %s, %s\ngerman: %s, %s\n", sprachen.english[0], sprachen.english[1],
                sprachen.deutsch[0], sprachen.deutsch[1]);
        }

        Calocybe

        1. hi!

          typedef struct {

          »»     char ** english;
          »»     char ** deutsch;

          } sprachen_struct;

          int main() {

          »»     sprachen_struct sprachen;
          »»     static char * english[] = {"man", "woman"};
          »»     static char * deutsch[] = {"Mann", "Frau"};

          »»     sprachen.english = english;
          »»     sprachen.deutsch = deutsch;

          »»     printf("english: %s, %s\ngerman: %s, %s\n", sprachen.english[0], sprachen.english[1],
          »»         sprachen.deutsch[0], sprachen.deutsch[1]);

          }

          Nur sind Hashes in Perl viel flexibler als das, was du da in C geschrieben hast :)

          Du hast recht, ein Hash ist nicht wirklich ein sortiertes Array. Trotzdem ist es per Definion ein Array. Und damit war das, was Jörk beschrieben hat, eindeutig ein zweidimensionales Array.
          "Richtige" sortierte Arrays von Arrays lassen sich genau auf die gleiche Art und Weise anlegen, nur erfolgt der Zugriff statt mit Schlüsseln dann eben über die Indizes.

          bye, Frank!

          1. Hallo Ihr alle!

            Welch' merkwürdige Wege eine solche Diskussion doch gehen kann.
            Sicherlich hat jede Programmiersprache ihre Eigenheiten. Da gibt es dann positive und negative. Was sich in der einen Sprache relative elegant lösen läßt, wird bei dem Versuch es in einer anderen Sprache ähnlich zu gestalten oft zu einem Schuß ins eigene Knie.

            Mag sein, daß man die mehrdimensionalen Arrays aus der guten alten Basic-Zeit nicht mit Perl zurecht basteln kann. Aber muß denn das sein? Oder geht eher darum, geschickt auf gewisse Elemtent zugreifen zu können. Und wie egal ist es eigentlich, ob ein Hash "Hash" heißt oder "assoziatives Array" oder gar "verkapptes mehrdimensionales Basic-Array unter Einbeziehung der perlschen Referenzsemantik" ???

            Vielleicht hat Robert sein Problem nicht so an den Tag legen können, daß wir genau wissen, wie die Ideale Antwort ausschaut. Geht es darum, ein Problem in den Griff zu bekommen oder eher darum die guten alten "mehrdimensionale variablenfelder" nutzen zu können.

            Selbst wenn letzteres der Fall sein sollte ...
            Bislang ging ich immer davon aus, daß die mehrdimensionalen Dinger in Basic in etwa so daher kamen: $var[3][5]. Möglicherweise sind meine C64 Kenntnisse dafür zu eingestaubt, aber hier hatte ich doch nur Zahlen als mögliche Indizes. Robert wollte doch "deutsch" für die Auswahl des Array nutzen. Ist denn da ein Hash nicht eine (gute) Möglichkeit?

            Jörk

            1. Hi Jörk,

              danke für dein verkapptes mehrdimensionales Basic-Array unter Einbeziehung der perlschen Referenzsemantik! Dieser thread hat sicher auch einiges an unterhaltungswert zu bieten (gemäß der normativen kraft des faktischen) ;-)

              Bei meinem problem sind mir einfach die zweidimensionalen felder aus basic eingefallen - a$(0, 1) hat das damals geheissen. Ob als index zahlen oder strings zu verwenden sind, ist eigentlich egal, hauptsache es geht in perl. Deine lösung mit hash-elementen, die auf ein array zeigen, ist
              offenbar quasi die übersetzung dieser basic-dinger nach perl. Genial.

              ciao,
              robert

          2. Hi again!

            Nur sind Hashes in Perl viel flexibler als das, was du da in C geschrieben hast :)

            Das stimmt natuerlich. Deswegen ist Perl ja auch eine Scriptsprache, im Gegensatz zu C. Nur erkaufst Du Dir diese Bequemlichkeit natuerlich durch hoeheren Speicherbedarf und sehr viel niedrigere Ausfuehrungsgeschwindigkeit. Das was ich da in C geschrieben habe, ist schlicht und einfach fuer das Problem massgeschneidert und dementsprechend optimiert, aber eben auch dementsprechend unflexibel. Wollte man eine aehnlich Flexibilitaet erlangen, muesste man in C das nachprogrammieren, was die Perlentwickler intern fuer Listen und Hashes gemacht haben. De facto muesste man die Daten in eine doppelt-verkettete Liste packen und geeignete Routinen zum Zugriff bereitstellen, idealerweise alles fein saeuberlich in ein Objekt verpackt. Fuer einen Hash implementiert man zwecks besserer Zugriffszeiten vielleicht eine Zusatztabelle, in der die Keys sortiert herumliegen und auf die zugehoerigen Values verweist. Daher sind Arrays und Hashes also sehr aehnlich, weshalb wohl auch der Begriff "assoziatives Array" entstanden ist.

            Ein Haufen Aufwand also, und dann ist die Geschwindigkeit auch nicht mehr soviel hoeher als bei einem Script. Und dafuer wurden die Scriptsprachen ja nun schliesslich geschaffen. Die niedrigere Geschwindigkeit faellt in vielen Faellen sowieso nicht ins Gewicht. Und es ist viel bequemer, nicht immer erst kompilieren und linken zu muessen. Und es ist viel portabler.

            Calocybe

            1. Hi!

              Nur sind Hashes in Perl viel flexibler als das, was du da in C geschrieben hast :)

              Das stimmt natuerlich. Deswegen ist Perl ja auch eine Scriptsprache, im Gegensatz zu C. Nur erkaufst Du Dir diese Bequemlichkeit natuerlich durch hoeheren Speicherbedarf und sehr viel niedrigere Ausfuehrungsgeschwindigkeit. Das was ich da in C geschrieben habe, ist schlicht und einfach fuer das Problem massgeschneidert und dementsprechend optimiert, aber eben auch dementsprechend unflexibel.

              In diesem Falle geht aber doch diese Unflexibilität bei Dir soweit, daß ich eben NICHT die Sprache in einer extra Variablen halten kann, so daß ich je nach deren Inhalt entweder die englische oder die deutsche Variante erhalte. Statt dessen muß ich hier den Programmcode anpassen ...

              Und solche Strukturen kann ich mir ja auch unter Perl basteln. Oder etwas einfacher - ich nutze einen weiteren Namensraum:
              package sprachen;
              my $english, $deutsch;

              package main;
              $sprachen::english = qw(man woman);
              $sprachen::deutsch = qw(Mann Frau);

              printf("english: %s, %s\ngerman: %s, %s\n", $sprachen::english[0], $sprachen::english[1],
                      $sprachen::deutsch[0], $sprachen::deutsch[1]);

              Wollte man eine aehnlich Flexibilitaet erlangen, muesste man in C das nachprogrammieren, was die Perlentwickler intern fuer Listen und Hashes gemacht haben. De facto muesste man die Daten in eine doppelt-verkettete Liste packen und geeignete Routinen zum Zugriff bereitstellen, idealerweise alles fein saeuberlich in ein Objekt verpackt.

              Ich denke mal, daß Hashes in Perl über Hashes realisiert sind, weswegen sie wohl auch so heißen. Das funktioniert ungefähr so:
              Ich habe ein Array, in dem ich meine Keys ablegen möchte bsp. Länge 100
              Zu jedem Key den ich dort ablegen möchte, berechne ich den Hash-Wert nach einer Formel, die sämtliche möglichen Schlüsselwerte auf einen Wert von 0-99 bringt. An dieser Stelle im Array lege ich dann das Objekt bzw. eine Referenz darauf ab. Nun kann es aber auch vorkommen, daß zwei unterschiedliche Keys den gleichen Hash-Wert haben. In diesem Falle kann ich entweder eine Liste an dem entsprechenden Element ablegen, oder im Array solange weiter suchen, bis ich einen freien Platz finde ... Nun weiß ich nicht, wie genau die Dinger in Perl realisiert sind. Aber sicher werden nicht alle Objekte in einer doppelt verketteten Liste durchsucht, wenn mit einem konkreten Key nach einem Wert suche!

              Fuer einen Hash implementiert man zwecks besserer Zugriffszeiten vielleicht eine Zusatztabelle, in der die Keys sortiert herumliegen und auf die zugehoerigen Values verweist. Daher sind Arrays und Hashes also sehr aehnlich, weshalb wohl auch der Begriff "assoziatives Array" entstanden ist.

              Assoziativ halt, weil Strings anstelle von Integern für die Keys verwendet werden.

              Jörk

              1. Hello again!

                In diesem Falle geht aber doch diese Unflexibilität bei Dir soweit, daß ich eben NICHT die Sprache in einer extra Variablen halten kann, so daß ich je nach deren Inhalt entweder die englische oder die deutsche Variante erhalte. Statt dessen muß ich hier den Programmcode anpassen ...

                Richtig. Es ist aber C, und nicht Perl. Deswegen wuerde man kaum etwas schreiben, was Deiner Zeile
                    $string = $sprachen{$language}->[1];
                direkt entspricht. Vielmehr wuerde man etwas wie

                char * GetTerm(char * language, int index) {
                        if (strcmp(language, "english") == 0) {
                            return sprachen.english[index];
                        } else {
                            return (strcmp(language, "deutsch") ? NULL : sprachen.deutsch[index]);
                        }
                    }

                bauen und dann mit
                    char * string = GetTerm(language, 1);
                aufrufen. Da man die Language aber sowieso im ganzen Programm des oefteren abfragt, wuerde man es eigentlich noch anders machen. Naemlich einfach int-Werte definieren (0-english; 1-deutsch usw.) und nur einmal die Strings anschauen und eine int-Variable dementsprechend setzen.

                Und solche Strukturen kann ich mir ja auch unter Perl basteln. Oder etwas einfacher - ich nutze einen weiteren Namensraum:
                package sprachen;
                my $english, $deutsch;

                Sicher kannst Du dafuer ein eigenes Modul schreiben, aber das ist dann doch schon etwas weit ausgeholt. Fuer ein Objekt mit Eigenschaften und Methoden mag das ja angebracht sein, aber fuer ein einfaches struct mit zwei Membern? Da finde ich Deine Hash-Methode viel besser (die ganz nebenbei auch noch sehr flexibel ist). Uebrigens wird sowas auch in der perldsc manpage empfohlen.

                Ich denke mal, daß Hashes in Perl über Hashes realisiert sind, weswegen sie wohl auch so heißen.

                Na gut, das klingt irgendwie naheliegend. *g* Leider kenne ich mich mit Hashfunktionen nicht aus. Jedoch frage ich mich, funktionieren die denn auch vernuenftig mit so dynamischen Dingen wie einem Perl-Hash? Denn schliesslich ist die Groesse eines solchen im vorneherein nicht bekannt. Da kann man nicht einfach einen Bereich von 0 bis 99 (oft zu klein) oder bis 99999 (meist zu gross, kann aber trotzdem auch zu klein sein) annehmen. Wie handlet man denn sowas, bzw. sind Hashes ueberhaupt fuer sowas vorgesehen?

                Aber sicher werden nicht alle Objekte in einer doppelt verketteten Liste durchsucht, wenn mit einem konkreten Key nach einem Wert suche!

                Natuerlich nicht. Man kann die Schluessel aber beim Einfuegen sortieren, sodass man immer in der Mitte einer Menge nachschaut, ob der dortige Wert groesser oder kleiner als der gesuchte ist und damit nur noch in einer der beiden Haelften weitersuchen muss. Dadurch wird die zu durchsuchende Menge bei jedem Nachschauen halbiert. Mit maximal 32 Vergleichen kannst Du so einen Wert in einer Menge von 4 Milliarden finden. Den Namen dieses Verfahrens habe ich leider vergessen. Allerdings setzt dieses Verfahren einen direkten Index-Zugriff auf ein Array voraus, welcher bei einer verketteten Liste nicht gegeben ist. Man muss sich deshalb noch durch die Liste durchhangeln, was wiederum Zeit kostet. Aber soviel nun auch wieder nicht; ist also auf jeden Fall weitaus schneller als alle Elemente der Reihe nach zu vergleichen.

                Assoziativ halt, weil Strings anstelle von Integern für die Keys verwendet werden.

                Mal so nebenbei, kann man eigentlich auch was anderes als Strings (bzw. in Strings umgewandelte Integer) verwenden? Mmh... macht das ueberhaupt Sinn?

                Calocybe