Cruz: Wieso ist dieser Array leer?

Hallo Leute,

mir ist grad etwas unerklärliches passiert.

Ich lese erstmal eine kleine Datenbank ein..

open (DB, "<$db") or die "Could not open $db";
@lines = <DB>;
close(DB);

Dann verarbeite ich sie spaltenweise zu Arrays:

split lines into arrays

$l=0;
foreach $line (@lines) {
chomp($line);

$i=0;  
for ($i=0;$i<$columns;$i++) {  
(${$headers[$i]}[$l],$line)=split(/\t/,$line,2);  
}  

$l++;
} # end foreach @lines

Dann noch ein kleines..

$test=join("<br>",@lines);

Und siehe da... @lines ist nach diesem Algorithmus leer! $test enthält jede Menge <br> s, also ist @lines immer noch ein langes Array, aber wo sind die Inhalte hingekommen?

Auf der Suche nach einer Antwort
Cruz

  1. Hallo Cruz!

    split lines into arrays

    $l=0;
    foreach $line (@lines) {

    Die Elemente von @lines werden nach und nach $line zugewiesen. Änderungen an $line ändern die Elemente im Array !!!
    Das folgende chomp zum Beispiel.

    chomp($line);

    »»  $i=0;
    »»  for ($i=0;$i<$columns;$i++) {
    »»  (${$headers[$i]}[$l],$line)=split(/\t/,$line,2);

    Hier wird nach und nach $line an den Tabulatoren aufgetrennt. Immer ein Element in das Array für die entsprechende Spalte und der Rest wieder nach $line. So wird $line Stück für Stück kürzer - bis es schließlich leer ist!!!

    »»  }

    $l++;
    } # end foreach @lines
    Und siehe da... @lines ist nach diesem Algorithmus leer! $test enthält jede Menge

    »»  s, also ist @lines immer noch ein langes Array, aber wo sind die Inhalte hingekommen?

    Wie gesagt, Stück für Stück gelöscht. Die Inhalte liegen nun in Arrays. Das Array @headers enthält pro Spalte ein Array. Dieses Spalten-Array enthält wiederum für jede Zeile ein Element ...

    Auf der Suche nach einer Antwort

    Ich hoffe, daß Du jetzt fündig geworden bist ;-)

    Jörk

    1. Die Elemente von @lines werden nach und nach $line zugewiesen. Änderungen an $line ändern die Elemente im Array !!!

      Hallo Jörk,

      bist du dir da sicher? Kannst du es beweisen? ;)
      In einem Jahr Perl Programmieren ist mir das noch nie aufgefallen, aber es wäre auf jeden Fall eine Antwort auf meine Frage. :)

      Danke
      Cruz

      1. hi!

        Die Elemente von @lines werden nach und nach $line zugewiesen. Änderungen an $line ändern die
        Elemente im Array !!!
        bist du dir da sicher? Kannst du es beweisen? ;)

        perldoc perlsyn:

        === cut ===
          Foreach Loops

        [...]

        The foreach' keyword is actually a synonym for the for' keyword, so
            you can use foreach' for readability or for' for brevity. (Or because
            the Bourne shell is more familiar to you than *csh*, so writing for'     comes more naturally.) If VAR is omitted, $_' is set to each value. If
            any element of LIST is an lvalue, you can modify it by modifying VAR
            inside the loop. That's because the `foreach' loop index variable is an
            implicit alias for each item in the list that you're looping over.
        === cut ===

        Beweis:

        === cut ===
        #!/usr/bin/perl

        @array = (1, 2, 3);

        print @array;
        for (@array)
        {
            $_++;
        }
        print @array;
        === cut ===

        bye, Frank!

        1. Ok jetzt bin ich beruhigt Danke schön!!

          Gruß an alle Helfer
          Cruz

  2. Hallo Cruz!

    $test=join("<br>",@lines);
    Und siehe da... @lines ist nach diesem Algorithmus leer!

    Woher weisst Du das? Vielleicht hat es ja jede Menge Elemente, die nur alle Nullstrings oder undef sind.
    Du kannst mit scalar(@lines) die Anzahl der Elemente feststellen. Ist diese groesser 0 (am besten == der Anzahl der Zeilen Deiner DB), hast Du vermutlich keine \t in Deinen Daten, sodass beim split() das $line geleert wird.
    Ist aber @lines wirklich leer, liegt der Fehler wohl woanders. Dann solltest Du vielleicht noch etwas mehr vom Source posten. @headers und $columns werden naemlich nirgendwo initialisiert.

    So lange

    1. Ist aber @lines wirklich leer, liegt der Fehler wohl woanders. Dann solltest Du vielleicht noch etwas mehr vom Source posten. @headers und $columns werden naemlich nirgendwo initialisiert.

      Hallo Calocybe,

      Ich habe es gründlich durchgetestet, der Array wird auf jeden Fall in diesem Block leer:

      split lines into arrays

      $l=0;
      foreach $line (@lines) {
      chomp($line);

      $i=0;  
      for ($i=0;$i<$columns;$i++) {  
      (${$headers[$i]}[$l],$line)=split(/\t/,$line,2);  
      }  
      

      $l++;
      } # end foreach @lines

      Wenn ich $test=join("<br>",@lines); genau vor dem Block einsetze, erhalte ich die komplette Datenbank, wie erwünscht. Aber wenn ich es direkt nach dem Block einsetze, dann enthält @lines nur noch leere trings.
      $headers und $columns werden natürlich vorher initialisiert.
      Was ich hier absolut nicht verstehe ist, daß dieser Block keinerlei Anweisung enthält, die die Elemente von @lines irgendwie verändern könnte. Eine Zuweisung zu $line in der foreach Schleife hat doch keinen Einfluss auf die Elemente.....oder?

      $x=$y bewirkt ja auch nicht, das $y danach leer ist.

      Gruß
      Cruz

      1. Hallo Cruz

        split lines into arrays

        $l=0;
        foreach $line (@lines) {

        Über $line änderst du auch @lines. Versuch mal statt dieser Zeile folgendes einzufügen
        foreach $temp (@lines) {
        $line = $temp;
        Das sollte das problem lösen. Den hier wird wirklich der Inhalt kopiert und nicht nur darauf verwießen

        chomp($line);

        »»  $i=0;
        »»  for ($i=0;$i<$columns;$i++) {
        »»  (${$headers[$i]}[$l],$line)=split(/\t/,$line,2);
        »»  }

        $l++;
        } # end foreach @lines

        Tschüs

        Daniel

    2. Ich meinte übrigens genau was du sagtest,
      @lines ist nicht leer, sondern es enthält nur leere Strings.
      Hab ich in meinem ersten posting vielleicht nicht so toll ausgedrückt.

      Sorry
      Cruz