Toon posts:

[perl] tabelwaarden in hash zetten

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben al een tyd bezig met dit probleem, en ik kom er maar niet uit, misschien dat iemand mij even op het goed spoor kan zetten.

ik heb een file met de volgende contents:
code:
1
2
3
4
5
6
1;0.99;0.000
1;0.95;0.004
1;0.05;3.84
1;0.01;6.64
1;0.001;10.83
etc etc etc


het zijn 3 waarden nu wil ik de inhoud in een hash zetten

code:
1
2
3
$waarden_hash{$df_hash}{$p_hash}=($waarde_hash);  
vb
$waarden_hash(1}{0.99}=(o.ooo)


dat probeer ik op de volgende manier:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
while (<CORPUS>) {
    chomp;
    #verwijder de /n's

    @waarden = split (/;/);
    #split op ; en zet in @waarden  

        foreach  my $waarde(@waarden) {
        #loop array waarden af
        
            my $df_temp=0;
            my $p_temp=1;
            my $waarde_temp=2;
            #hulpvariabelen voor elementen, df is 0de element uit @waarden, p is 1ste element....

            my $df_hash = $waarden[$df_temp];
            my $p_hash = $waarden[$p_temp];
            my $waarde_hash = $waarden[$waarde_temp];
            
            $waarden_hash{$df_hash}{$p_hash}=($waarde_hash);
            #zet benodigde waarden in hash

            $df_temp+=3;
            $p_temp+=3;
            $waarde_temp+=3;
            #ga 3 elementen verder, hier staat de volgende benodigde df of p of waarde
        
        }
}


ik loop de file door, split hem, ik weet dat het 0de,3de,6de... element bv de benodigde df waarde is en voor p is dat de 1ste,4de... element

[ Voor 4% gewijzigd door Verwijderd op 18-05-2004 21:28 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:14
Tja, je blijft wel een beetje aanmodderen elke keer. Ik kan nu wel weer een uitleg geven van wat er allemaal mis gaat en hoe het wel moet, maar misschien is het veel handiger als je eerst probeert om de basisprincipes achter een scripting taal als Perl te begrijpen, door een Perl tutorial ofzo door te nemen. drm suggereerde ook al zoiets.

Er zijn erg veel Perl tutorials te vinden; kies er eentje die je ligt en ga daar eerst eens mee aan de slag.

edit:
Verder stoor ik me ook een beetje aan de manier waarop je het probleem hier brengt. Je hebt nog helemaal niet zelf uitgezocht waarhet ongeveer mis gaat (en dat betekent in de praktijk: tot waar het goed gaat). Sterker nog, je vermeldt niet eens wat het door jouw geobserveerde foute gedrag is (je vermeldt wel wat je bedoeling is; een goed begin, maar slechts het halve werk). Nu kan ik in dit geval uit de code wel ongeveer raden wat er allemaal mis gaat en hoe dat te corrigeren is, maar het zou veel nuttig zijn als je tenminste zou proberen dit zelf uit te zoeken. Je zou dan kunnen kijken wat de waarden van de variabelen zijn op verschillende punten in de code (en in verschillende iteraties van de lus).

Het spijt me om het zo bot te zeggen, maar als je weigert om je in de semantiek van een programmeertaal te verdiepen zul je nooit leren programmeren.

[ Voor 44% gewijzigd door Soultaker op 18-05-2004 21:41 ]


Verwijderd

Topicstarter
Soultaker schreef op 18 mei 2004 @ 21:36:
Tja, je blijft wel een beetje aanmodderen elke keer. Ik kan nu wel weer een uitleg geven van wat er allemaal mis gaat en hoe het wel moet, maar misschien is het veel handiger als je eerst probeert om de basisprincipes achter een scripting taal als Perl te begrijpen, door een Perl tutorial ofzo door te nemen. drm suggereerde ook al zoiets.

Er zijn erg veel Perl tutorials te vinden; kies er eentje die je ligt en ga daar eerst eens mee aan de slag.
ik heb al wat boeken doorgewerkt... maar soms blijf je wel eens ergens steken op een probleem, ik ben dus geen starter..

heb ook dit bedacht:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
while (<CORPUS>) {
    chomp;
    #verwijder de /n's

    @waarden = split (/;/);
    #split op ; en zet in @waarden  

    my $df_temp=0;
    my $p_temp=1;
    my $waarde_temp=2;
        
    foreach  (@waarden) {
    
    #loop array waarden af
        
            
            #hulpvariabelen voor elementen, df waar is 0de element uit @waarden p is 1ste....

                
            %waarden_hash=(@waarden[$df_temp] => @waarden[$p_temp] => @waarden[$waarde_temp])
            #zet benodigde waarden in hash

            $df_temp+=3;
            $p_temp+=3;
            $waarde_temp+=3;
            #ga 3 elementen verder, hier staat de volgende benodigde df of p of waarde
            
        

        }
}

[ Voor 29% gewijzigd door Verwijderd op 18-05-2004 21:42 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:14
Zie ook mijn edit.

Je code is tot en met regel 6 in orde. Daarna gaat het helemaal mis. Kun je uitleggen waarom je opeens een foreach statement gebruikt en waarom je die _temp variabelen introduceert? Als je de code in regels 8 tot en met 28 wegdenkt, wat denk je dan dat er steeds in @waarden komt te staan? (En hier komt het verhaal over uitzoeken en debuggen ter sprake: je kunt dit namelijk makkelijk testen door print join(", ", @waarden), "\n" na je assignment te zetten).

Als je er goed van bewust bent wat er in @waarden staat dan zou je eigenlijk niet eens moeten twijfelen over wat je verder moet doen om de rest van het programma te schrijven. Sterker nog: je bent in die situatie slechts 1 regel verwijderd van een prima oplossing!

edit:
Nu niet heel belangrijk, maar je gebruikt die 'my' declaraties ook niet echt consequent. Ze zijn alleen verplicht als je strict code schrijft (zet dan "use strict;" bovenaan je code), maar ik zou zeggen: gebruik ze ofwel over (zodat je inderdaad stricte code hebt) of nergens (want als je code niet strict is heb je er toch niets aan).

[ Voor 21% gewijzigd door Soultaker op 18-05-2004 21:46 ]


Verwijderd

Topicstarter
Soultaker schreef op 18 mei 2004 @ 21:45:
Zie ook mijn edit.

Je code is tot en met regel 6 in orde. Daarna gaat het helemaal mis. Kun je uitleggen waarom je opeens een foreach statement gebruikt en waarom je die _temp variabelen introduceert? Als je de code in regels 8 tot en met 28 wegdenkt, wat denk je dan dat er steeds in @waarden komt te staan? (En hier komt het verhaal over uitzoeken en debuggen ter sprake: je kunt dit namelijk makkelijk testen door print join(", ", @waarden), "\n" na je assignment te zetten).

Als je er goed van bewust bent wat er in @waarden staat dan zou je eigenlijk niet eens moeten twijfelen over wat je verder moet doen om de rest van het programma te schrijven. Sterker nog: je bent in die situatie slechts 1 regel verwijderd van een prima oplossing!

edit:
Nu niet heel belangrijk, maar je gebruikt die 'my' declaraties ook niet echt consequent. Ze zijn alleen verplicht als je strict code schrijft (zet dan "use strict;" bovenaan je code), maar ik zou zeggen: gebruik ze ofwel over (zodat je inderdaad stricte code hebt) of nergens (want als je code niet strict is heb je er toch niets aan).
sorry die my's worden globaal ergens anders in het programma gedeclareerd, uiteraard gebruik ik use strict;

ik weet wat er in @waarden komt te staan, dit heb ik getest met een print "$_\n" daarom weet ik dus ook welke elementen ik wil hebben. Die foreach gebruik ik om de array door te lopen en wij zijn verplicht geleerd zijn een foreach te gebruiken in plaats van een for loop, alleen in dit geval is dat misschien inderdaad niet okay.

[ Voor 3% gewijzigd door Verwijderd op 18-05-2004 22:24 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:14
Ik bedoelde niet dat je een for-lus moet gebruiken in plaats van een foreach-lus; ik bedoel dat je helemaal geen binnenste lus nodig hebt. Wat denk jij dan dat er elke iteratie in @waarden staat? Ik denk steeds de drie waarden die op de laatst gelezen regel stonden. Waarom zou je daar over willen itereren? Je kunt er al direct mee doen wat je er mee WIL doen!

Misschien zie je mijn punt beter als ik regel 5 herschrijf naar:
Perl:
5
my($df_hash, $p_hash, $waarde_hash) = split (/;/);

Verwijderd

Topicstarter
Soultaker schreef op 18 mei 2004 @ 22:31:
Ik bedoelde niet dat je een for-lus moet gebruiken in plaats van een foreach-lus; ik bedoel dat je helemaal geen binnenste lus nodig hebt. Wat denk jij dan dat er elke iteratie in @waarden staat? Ik denk steeds de drie waarden die op de laatst gelezen regel stonden. Waarom zou je daar over willen itereren? Je kunt er al direct mee doen wat je er mee WIL doen!

Misschien zie je mijn punt beter als ik regel 5 herschrijf naar:
Perl:
5
my($df_hash, $p_hash, $waarde_hash) = split (/;/);
stom stom stom, ik zit vandaag weer veel te lang achter die computer, en even afstand nemen is vaak toch beter;

code:
1
2
3
4
5
6
7
8
9
10
11
12
while (<CORPUS>) {
    chomp;
    #verwijder de /n's

    @waarden = split (/;/);
    #split op ; en zet in @waarden  

    
    $waarden_hash{$_[0]}{$_[1]}= $_[2]
    #zet benodigde waarden in hash waarden_hash {df}{p}=waarde
    
}


volgens mij moet dit beter werken, ik moet nu alleen nog even verder gaan beredeneren hoe ik de waardes eruit ga halen, mijn programma geeft straks bijvoorbeeld aan dat df = 1 en p = 0.95 en dan moet de waarde uit de hash worden gelezen.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:14
Zo kan het ook. Gebruik dan liefst ofwel @waarde (en op regel 9 refereer je dan aan $waarde[0], $waarde[1] en $waarde[2]) of laat de hele assignment aan @waarde weg. In dat geval wordt de functie:

Perl:
1
2
3
4
while(<CORPUS>) {
    chomp; split /;/;
    $waarden_hash{$_[0]}{$_[1]} = $_[2];
};
Bedenk dat $_ en @_ default variables zijn; die kun je gebruiken als je geen zin hebt om resultaten aan 'echte' variabelen toe te kennen. In echt nette code zou je die misschien niet moeten gebruiken; omwille van de leesbaarheid zouden alle variabelen dan expliciet benoemd moeten worden (dat maakt ook duidelijk wat de inhoud van variabele betekent, omdat de variabele zelf een zinnige naam heeft). In dat geval zou je code zoiets worden:
Perl:
1
2
3
4
while(my $line = <CORPUS>) {
    chomp $line; my @waarden = split /;/;
    $waarden_hash{$waarden[0]}{waarden[1]} = $waarden[2];
};
Ik vind de eerste variant altijd wel aardig en ook wel acceptabel omdat 'ie lekker kort is en het gebruik van default variables inherent is aan het gebruik van Perl. Desalniettemin is de tweede variant zeker leesbaarder en is het belangrijk om, voor welke methode je ook kiest, een methode consequent te gebruiken.

Ik hoop dat je er de volgende keer wel zelf uitkomt, want ik heb nog steeds het idee dat je een aantal niet goed begrijpt. Maar ok, ik hoop dat je tenminste wat geleerd hebt en je de volgende keer op z'n minst wat verder komt.

[ Voor 3% gewijzigd door Soultaker op 19-05-2004 03:19 ]


Verwijderd

Topicstarter
ik ben er helemaal uit gekomen, bedankt voor jullie tips!

dit is een fragment uit mijn script waar ik het gebruik:

code:
1
2
3
4
5
6
7
8
9
while (<TABLE>) {
        chomp;
        #verwijder de /n's

        ( $df_hash, $p_hash, $waarde ) = split (/;/);
        #split op ; en zet in benodigde variabelen  

        $waarden_hash{$df_hash}{$p_hash}= $waarde;
        #zet benodigde waarden in hash waarden_hash {df}{p}=waarde


en dit vervolgens om de matrix te printen

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
if ($ARGV[0] eq "-tab") {

        print "\n";

        foreach my $df (sort(keys(%{$waarden_hash{$df_hash}}))) {
            print "\t$df"
            #print df waarden 
            }
        print "\n";

        
        foreach my $p (sort(keys(%waarden_hash))) {
        
            print "$p";
            # print de p waarde

            foreach my $df (sort(keys(%{$waarden_hash{$p}}))) {
            
                print "\t$waarden_hash{$p}{$df}";
                # geef de waarde uit waarden_hash weer

            }
        
        print "\n";
        }

    print "\n";
 
    exit;
    #termineer, table is weergegeven

    }

[ Voor 8% gewijzigd door Verwijderd op 19-05-2004 08:59 ]

Pagina: 1