Strona 1 z 3 123 OstatniOstatni
Pokaż wyniki 1 do 10 z 22

Temat: [Perl]wczytywanie liczb do tablicy

  1. #1

    Domyślnie [Perl]wczytywanie liczb do tablicy

    Mam plik.txt z danymi odzielonymi przecinkami:
    12,34,56
    23,4,5
    12,3,4
    123,1,1

    Chcialbym wczytac te dane do tablicy, tak aby moc sie odwloywac do odpowiedniego elementu, np. chce wyciagnac trzeci element z drugiego wiersza, czyli 5.

    Wczytalam dane z pliku i podzielilam je wg przecinka:
    Kod:
    open (K, 'plik.txt'); while (<K>) {
       $line = $_;
       @d = split(',',$line);
       push(@date,@d);
    }
      close(K);
    
      print @date;
    Niestety nie wiem co dalej mam zrobic, by uzyskac moj zaplanowany cel.
    tzn nie wiem jak sie odwolac do tej tablicy. Czy moge prosic o jakies wskazowki?
    Ostatnio edytowane przez Gosik : 01-10-2013 - 20:03

  2. #2

    Domyślnie

    Troche poprawilam swoj kod.

    Kod:
    open (K, 'plik.txt'); while (<K>) {
       chomp;
       $line = $_;
       @d = split(',',$line);
       push @date,\@d;
    }
      close(K);
    
      print @date;
      print $date[0]->[2];
    Kod ten powoduje, ze mam wyswietlony trzeci element z ostatniego wiersza.

    Co w tym kodzie mam zle? Dlaczego nie wyswietla mi elementu z drugiego wiersza i trzeciej kolumny?

  3. #3
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    Do debugowania kodu jesli nie jestes pewna jak wygladaja Twoje dane, swietnie spisuje sie takie cos...

    Kod:
    use Data::Dumper;
    print Dumper \@data;
    teraz mozesz zobaczyc jak wygladaja tablice, hashe i jedno zapakowane w drugie przez referencje... bez tego modulu zginalbym wiele razy a tak chwila, jeden print i juz wiem co jest co.

    Kod:
    print Dumper \$data[0];
    Juz wiesz jak wyglada pierwszy wiersz - powinna byc tablica

    BTW, uzycie referencji tak jak to robisz uzyskujac tablice tablic, to jest podstawa w dalszym obiektowym programowaniu w Perlu - to tak jak pointer w C. Zalety sa ogromne:
    1. nie kopiujesz danych przekazujac je do funkcji jako parametry tylko przekazujesz wskaznik odwolujacy sie do oryginalnej zmiennej
    2. mozesz przekazywac zmienne o innym zakresie leksykalnym, ktore normalnie nie istnialyby w tym segmencie kodu - przekazywanie wartosci normlanie i zbieranie wynikow byloby bardzo trudne w wiekszym projekcie i podatne na wystapienie glupich bledow (wiem bo sam sie na to nie raz zlapalem)
    3. uzywajac modulow ktore uzywaja zapisu obiektowego, Twoje obiekty nie sa niczym innym jak referencje

    nie martw sie tym co napisalem wyzej - wazne jest to ze idziesz w dobrym kierunku a do tych 3 elementow dojdziesz sama we wlasnym czasie
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  4. #4

    Domyślnie

    [QUOTE=TQM;62239]Do debugowania kodu jesli nie jestes pewna jak wygladaja Twoje dane, swietnie spisuje sie takie cos...

    Kod:
    use Data::Dumper;
    print Dumper \@data;
    Wielkie dzieki za te info.

    Teraz wiem w czym tkwi problem. Mianowicie do kazdej tablicy jest wczytywany oststni wiersz.
    Tylko nie wiem dlaczego...

    Moze widzisz dlaczego tak sie dzieje i gdzie jest moj blad w rozumowaniu?

  5. #5
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    To nie blad w rozumowaniu :-)

    Kod wyglada ok ale nie dziala. Moge jedynie zgadywac, ze chodzi o to, ze odkladasz do @date referencje do globalnej zmiennej @d, globalnej i deklarowanej wewnatrz petli... jak teraz przepiszesz wartosc zmiennej wczytujac nastepny wiersz, to zmieniasz to co juz odlozylas do @date :-)

    Piszac w perlu warto dodac dwa moduly, strict i warnings. Strict nie pozwoli na takie luzne deklarowanie zmiennych, trzeba je zadeklarowac uzywajac my, our albo local. Generalnie pomaga to w sledzeniu zasiegu zmiennych i znajdywaniu literowek w kodzie, bo program od razu poda ze uzywasz nieznanej zmiennej. Uzycie warnings dodatkowo daje informacje o tym, ze np zmienna ktorej uzywasz jest undef, czyli logika skryptu bedzie wariowac bo szukasz wartosci aby wstawic do zmiennej, wszystko wyglada dobrze a skrypt nie dziala... bo zmienna jest undef bo albo dane byly nieprawidlowe albo regex zle zapisany albo cos innego. Warnings ostrzega tez, jesli w ramach jednego bloku {} ponownie deklarujesz zmienna o tej samej nazwie.

    Ogolnie aby pisac w Perlu i nie popelniac bledow warto od poczatku zapamietac:
    Kod:
    use strict;
    use warnings;
    Kazdy moj skrypt od tego sie zaczyna, no chyba ze jest to 1-linijkowiec odpalany prosto z wiersza polecen :-) W kazdym innym wypadku mam te dwa moduly.

    Poprawiona wersja kodu wyglada tak:
    Kod:
    #!usr/bin/perl
    use Data::Dumper;
    use strict;
    use warnings;
    
    my @date;
    open (K, 'plik.txt'); 
    while (<K>) {
       chomp;
       my @d = split(/,/);
       push @date,\@d;
    }
    close(K);
    print Dumper \@date;
    a wynik dzialania taki:
    Kod:
    $VAR1 = [
              [
                '12',
                '34',
                '56'
              ],
              [
                '23',
                '4',
                '5'
              ],
              [
                '12',
                '3',
                '4'
              ],
              [
                '123',
                '1',
                '1'
              ]
            ];
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  6. #6

    Domyślnie

    Swietnie! Bardzo dziekuje za pomoc, juz jest jakis progress

    Dzialam dalej i nasunelo mi sie jescze jedno pytanie.

    Mam dwa pliki z danymi:
    plik1.txt
    4,11,23,1
    5,33,44,2
    6,44,55,2

    plik2.txt

    1,23,4
    2,334,43
    3,44,5
    4,55,6
    5,33,4

    Porownuje pierwsze wyrazy z pliku i jesli sa takie same, wrzucam do tablicy.
    Daze do tego by otrzymac plik3.txt w nastepujacej postaci:
    4,11,23,1,4,55,6
    5,33,44,2,5,33,4

    stworzylam taki kod:
    Kod:
    my @tab;
     for (my $i=0; $i<=$#date; ++$i){
       if ($date[$i]->[0] = $date2[$i]->[0]){
        my @b = ($date[$i],$date2[$i]);
         push @tab, \@b;
    #     push @tab,\@date2[$i]; 
        }
      }
    
     print $tab[0]->[1][2];

    Moje pytanie brzmi:
    jak poprawnie powinnam sie odwolywac do tablicy @tab?
    Jak widac probowalam to uczynic w nastepujacy sosob:
    Kod:
    print $tab[0]->[1][1]
    Ale niestety nie jest to poprawne.

    Czy w tej kwestii moglabym rowniez liczyc na wskazowke?

  7. #7
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    Ok, chyba rozumiem o co chodzi choc nie wynika to z opisu a raczej z kodu

    Zacznijmy od poczatku:
    Kod:
    if ($date[$i]->[0] = $date2[$i]->[0]){
    Przypisujesz wartosc zamiast sprawdzac czy sa sobie rowne, powinno byc ==

    Generalnie potrzebujesz przejsc w petli przez kazdy z elementow @date i dla kazdego z nich sprawdzic kazdy z @date2 - jesli pierwszy element list sie zgadza, wyswietlasz obie listy razm w 1 linii.

    Kod:
    for (my $d1=0; $d1<=$#date; $d1++) {
      for (my $d2=0; $d2<=$#date2; $d2++) {
        if ($date[$d1]->[0] == $date2[$d2]->[0]) {
          # sklejmy obie listy i wyswietlmy - lista zlozona z list to jednowymiarowa lista
          # robimy dereferencje list tablic, nawiasy klamrowe sa dla czytelnosci 
          my @tmp = (@{$date[$d1]}, @{$date[$d2]});
          print join ',', @tmp . "\n";
        }
      } 
    }
    mniej wiecej tak, pisane w glowie i nie sprawdzalem czy dziala
    Dereferencje skalara robisz jako $$ref, tablicy jako @$ref albo @{$ref} dla czytelnosci, itd. Jesli robisz tak to musisz wartosc przypisac gdzies indziej, do innej zmiennej.

    Kod:
    sub costam {
      my $hashref = shift;
      my %hash = %$hashref;
      print $hash{klucz};
    }
    costam(\%jakishash);
    albo dokladnie to samo zapisane inaczej

    Kod:
    sub costam {
      my $hashref = shift;
      print $hashref->{klucz};
    }
    costam(\%jakishash);
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

  8. #8

    Domyślnie

    Cytat Napisał TQM Zobacz post
    Ok, chyba rozumiem o co chodzi choc nie wynika to z opisu a raczej z kodu

    Zacznijmy od poczatku:
    Kod:
    if ($date[$i]->[0] = $date2[$i]->[0]){
    Przypisujesz wartosc zamiast sprawdzac czy sa sobie rowne, powinno byc ==
    Ok, a gdy bedziemy porownywac wartosci z kolumn, gdy sa w postaci daty, np:
    kolumna z 1 pliku:
    11:26:11
    11:26:12
    11:26:13
    ......

    kolumna z 2 pliku:

    11:26:09.126
    11:26:10.126
    11:26:11.126
    11:26:12.126
    ....

    Niestety przy warunku == mam wyrzucany blad:
    Use of uninitialized value in numeric eq (==) at.

    Probowalam rowniez zamiast == zastosowac eq, ale rowniez lipa. Dziala tylko dla stringow.

    Chcialabym zapytac, jak moge z tego wybrnac.
    Ostatnio edytowane przez Gosik : 01-13-2013 - 09:59

  9. #9

    Domyślnie

    Cytat Napisał Gosik Zobacz post
    Ok, a gdy bedziemy porownywac wartosci z kolumn, gdy sa w postaci daty, np:
    kolumna z 1 pliku:
    11:26:11
    11:26:12
    11:26:13
    ......

    kolumna z 2 pliku:

    11:26:09.126
    11:26:10.126
    11:26:11.126
    11:26:12.126
    ....

    Niestety przy warunku == mam wyrzucany blad:
    Use of uninitialized value in numeric eq (==) at.

    Probowalam rowniez zamiast == zastosowac eq, ale rowniez lipa. Dziala tylko dla stringow.

    Chcialabym zapytac, jak moge z tego wybrnac.
    Troche pokombinowalam.
    Stworzylam 2 funkcje do daty (ze wzgledu na fakt, ze maja troche inna postac):

    Kod:
    sub my_format {
        $_[0] =~ /(\d\d):(\d\d):(\d\d)/;   
        return "$1:$2:$3";    
    }
     
    sub my_format2 {
        $_[0] =~/(\d\d):(\d\d):(\d\d).(\d\d\d)/; 
        return "$1:$2:$3";
    }
    
    
    
    for (my $i=0; $i<=$#date; $i++) {
      for (my $j=0; $j<=$#date2; $j++) {
        if (my_format($date[$i]->[0]) == my_format2($date2[$j]->[0])) {
          # sklejmy obie listy i wyswietlmy - lista zlozona z list to jednowymiarowa lista
          # robimy dereferencje list tablic, nawiasy klamrowe sa dla czytelnosci 
          my @tmp = (@{$date[$i]}, @{$date[$j]});
          print join ',', @tmp . "\n";
        }
      } 
    }
    No i niestety jeszcz wyskakuje problem z porownaniem == :
    Argument "11:26:11" isn't numeric in numeric eq (==) at

  10. #10
    Zarejestrowany
    Jun 2006
    Skąd
    rand(.eu)
    Postów
    8,748

    Domyślnie

    Sorry, nie czytam kodu bo blad jest gdzie indziej.

    == dziala dla liczb
    eq dziala dla stringow

    ... ale Twoje pliki nie maja identycznych linii, bo jedno ma hh:mm:ss a drugie ma hh:mm:ss.nnn, wiec nie mozna ich porownac w zaden sposob bo na 10000% nie beda sobie rowne :-)

    Co potrzebujesz to wyrazenie regularne, czyli ze linia z drugiego pliku musi zaczynac sie od linii z pierwszego. w skrocie:

    Kod:
    if ($druga =~ /^$pierwsza/) { print "Dopasowanie OK\n" };
    ctrl-alt-del.cc - soft reset site for IT admins and other staff :-)

Strona 1 z 3 123 OstatniOstatni

Zasady Postowania

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów
  •  
Subskrybuj