Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]11131[/thread]

Probleme mit splice. Warum geht dat net???



<< |< 1 2 >| >> 12 Einträge, 2 Seiten
Alvin
 2008-01-12 17:22
#104642 #104642
User since
2007-12-28
9 Artikel
BenutzerIn
[default_avatar]
Hi,

ich hab mal wieder ne Frage. Ich habe folgendes programmiert (teilweise dank eurer Hilfe!):

#USAGE: ./alvin.pl 6 3

Code (perl): (dl )
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
33
34
#!/usr/bin/perl
use strict;
use warnings;

my $init_popsize=$ARGV[0]-1;
my $maxtime=$ARGV[1];

my @age;
my @gender;
my @weight;
my @population = (0..$init_popsize);

for my $i(0..$#population){
    $age[$i]=int(rand(10));                  #Alter
    my $r1=rand();
    if($r1<=0.4){                                 #Geschlecht (0=männlich, 1=weiblich)
        $gender[$i]=0;
        }
    else{
        $gender[$i]=1;
        }
    my $r2=rand();
    if ($r2<=0.3){                                #Gewicht
        $weight[$i]=0;
        }
    elsif ($r2>0.3 && $r2<=0.6){
        $weight[$i]=1;
        }
    else{
        $weight[$i]=2;
        }
    printf "$age[$i] $gender[$i] $weight[$i]\n";
    } 
printf "\n";



Aussen:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
for my $t (1..$maxtime){
     
    Innen: for my $i (0..$#population){

        $age[$i]++;
        
        if ($age[$i]>=10){
            splice (@age, $i, 1);
            splice (@weight, $i, 1);
            splice (@gender, $i, 1);
            splice (@population, $i, 1);
            # $age[$i]++;
            next Innen;
       }
   }

for my $i (0..$#population){

printf "$age[$i] $gender[$i] $weight[$i]\n";
}
my $population=$#population+1;
printf "\npopulation:  $population\n";
}



So...nun mein Problem: als Ausgabe erhalte ich unter anderem für das Alter age[i] z.B.:

4
5
7
9
1
7

soweit so gut, aber wenn jetzt, wie gewünscht, die 9 durch splice rausfliegt und alle um age++ um eins erhöht werden kommt folgendes

5
6
8
1
8

die 9 ist weg, wie gewünscht, die 4,5,7 und die letzte 7 wurden um 1 erhöht, aber die 1 wurde nicht erhöht. Warum???
Hab schon dran gedacht nach den splice Befehlen i-- zu machen, aber bringt auch nix. Aber wenn ich nach den splice Befehlen das oben auskommentierte age++ benutze geht es, aber ich kapier nicht warum er das nicht ohne dieses macht???

Danke schon mal für die Hilfe!!!

P.S. Hoffe mein Problem ist verständlich geworden???

edit pq: perl-tags hinzugefügt
Linuxer
 2008-01-12 18:42
#104644 #104644
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
Code beautified && in Perl-Tags gesetzt:
Keine weitere Aktion; Anmerkung am Ende.

Code (perl): (dl )
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/perl
use strict;
use warnings;

#USAGE: ./alvin.pl 6 3

my $init_popsize = $ARGV[0] - 1;
my $maxtime      = $ARGV[1];

my @age;
my @gender;
my @weight;
my @population = ( 0 .. $init_popsize );

for my $i ( 0 .. $#population ) {
    $age[$i] = int( rand(10) );    #Alter
    my $r1 = rand();
    if ( $r1 <= 0.4 ) {            #Geschlecht (0=männlich, 1=weiblich)
        $gender[$i] = 0;
    }
    else {
        $gender[$i] = 1;
    }
    my $r2 = rand();
    if ( $r2 <= 0.3 ) {            #Gewicht
        $weight[$i] = 0;
    }
    elsif ( $r2 > 0.3 && $r2 <= 0.6 ) {
        $weight[$i] = 1;
    }
    else {
        $weight[$i] = 2;
    }
    printf "$age[$i] $gender[$i] $weight[$i]\n";
}
printf "\n";

Aussen: for my $t ( 1 .. $maxtime ) {

  Innen: for my $i ( 0 .. $#population ) {

        $age[$i]++;

        if ( $age[$i] >= 10 ) {
            splice( @age,        $i, 1 );
            splice( @weight,     $i, 1 );
            splice( @gender,     $i, 1 );
            splice( @population, $i, 1 );

            # $age[$i]++;
            next Innen;
        }
    }

    for my $i ( 0 .. $#population ) {

        printf "$age[$i] $gender[$i] $weight[$i]\n";
    }
    my $population = $#population + 1;
    printf "\npopulation: $population\n";
}


Anderes Thema als das gefragte:

Du benutzt printf. Warum?

Wenn Du keine Formatierung der Ausgabe machst, dann nimm print;
wenn Du was formatieren willst, dann printf.
Denn ansonsten ist das eher eine Kanone für den Spatz.

Code (perl): (dl )
1
2
3
$i = 5.5;
print "$i unformatiert\n";
printf "%2.5f formatiert\n", $i;
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
murphy
 2008-01-12 19:25
#104647 #104647
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Alvin+2008-01-12 16:22:14--
[...] die 9 ist weg, wie gewünscht, die 4,5,7 und die letzte 7 wurden um 1 erhöht, aber die 1 wurde nicht erhöht. Warum???
Hab schon dran gedacht nach den splice Befehlen i-- zu machen, aber bringt auch nix.
[...]

Du hast Dir die Frage fast schon selbst beantwortet: Mittels splice entfernst Du ein Element aus dem Array, lässt die Schleifenvariable aber trotzdem erst beim nächsten Index weiterlaufen, wodurch ein Element übersprungen wird.

Nach der Spliceoperation $i-- auszuführen bringt auch nichts, da $i sofort danach vom Schleifenkopf neu gesetzt wird.

Eine mögliche Lösung wäre, an dieser Stelle keine foreach-Schleife sondern eine klassische for-Schleife zu verwenden:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
...
Innen: for (my $i = $[; $i <= $#population; $i++) {
  ...
  if (...) {
    ... splices ...
    $i--
  }
}
...


Linuxer+2008-01-12 17:42:27--
[...]
Wenn Du keine Formatierung der Ausgabe machst, dann nimm print;
wenn Du was formatieren willst, dann printf.
Denn ansonsten ist das eher eine Kanone für den Spatz.
[...]

printf ist außerdem gefährlich, wenn als erstes Argument kein konstanter String übergeben wird. Also entweder
Code (perl): (dl )
printf 'Das ist ein String: %s', $irgendwas;

oder
Code (perl): (dl )
print "Das ist ein String: $irgendwas";

aber bitte nicht
Code (perl): (dl )
printf "Das ist ein String: $irgendwas";
When C++ is your hammer, every problem looks like your thumb.
topeg
 2008-01-12 20:23
#104650 #104650
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
oder:
Code (perl): (dl )
Innen: for my $i (reverse( 0 .. $#population)) {

"reverse" dreht die Liste um.

wenn du Interesse hast, dein Programm mal etwas anders geschrieben:
Code: (dl )
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/perl
use strict;
use warnings;

#USAGE: ./alvin.pl 6 3

# die Ausgabe in einer eigenen Funktion
# dann schreibt man es nicht unnötig doppelt.
sub show_person
{
my $person=shift(@_);
my $age=$person->{age}; # Wert aus einer Hashreferenz lesen.
my $gender=$person->{gender};
my $weight=$person->{weight};
print "$age\t$gender\t$weight\n";
}

# $wert=(<bedingung>)?$a:$b ist gleich zu if(<bedingung>){$wert=$a}else{$wert=$b}
my $init_popsize = $ARGV[0] ? $ARGV[0] - 1 : 10 ; # wenn keine Angabe dann 10 annehmen
my $maxtime = $ARGV[1] ? $ARGV[1] : 10; # wenn keine angabe dann 10 Durchläufe machen

my @population;

for my $i (0..$init_popsize)
{
my $age=int( rand(10) );

my $gender=1; #Geschlecht (0=männlich, 1=weiblich)
$gender=0 if( rand(1) <= 0.4); # einen if-Zweig gespart.

my $random=rand(1);
my $weight=2;
if ( $random <= 0.3 )
{ $weight=0; }
elsif ( $random > 0.3 && $random <= 0.6 )
{ $weight=1; }

my %person=(age=>$age, gender=>$gender, weight=>$weight); # ein Hash der alle werte enthält
push(@population,\%person); # Referenz auf den Hash ans Array anhängen

show_person(\%person);
}
print "\n";

Aussen: for my $t ( 1 .. $maxtime )
{
print "\nTIME: $t\n";

Innen: for my $i (reverse( 0 .. $#population ))
{
my $person=$population[$i]; # referenz aus dem Array lesen
$person->{age}++;
splice( @population, $i, 1 ) if($person->{age} >= 10);
}

for my $person (@population) # hier kann man das array so durchlaufen lassen
{ show_person($person); }

print "population: ".@population."\n"; # im Skalarkontext gibt @array die Anzahl der enhaltenen Elemente zurück.
}


Alle Daten in einem Hash zu speichern mach das ganze doch übersichtlicher.
Alvin
 2008-01-13 19:13
#104671 #104671
User since
2007-12-28
9 Artikel
BenutzerIn
[default_avatar]
Hi,

vielen Dank!!! Das benutzen der for-Schleife hat das Problem gelöst! Da hätte ich mich echt tot gesucht.

Wegen dem printf, das wußte ich nicht! Werde in Zukunft drauf achten!!!

@topeg, vielen Dank, mit den Hash's wollte ich mich eh mal beschäftigen.

Aber noch ne kleine Frage, Du hast geschrieben:

my $init_popsize = $ARGV[0] ? $ARGV[0] - 1 : 10 ; # wenn keine Angabe dann 10 annehmen
my $maxtime = $ARGV[1] ? $ARGV[1] : 10; # wenn keine angabe dann 10 Durchläufe machen

Ist das schon funktionsfähig mit den Fragezeichen. oder muss da eine if-Abfrage rein? Ich frag so doof, weil es bei mir da eine Fehlermeldung gab.
Linuxer
 2008-01-13 19:46
#104672 #104672
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
Das ist funktionsfähig. Das ist der ternäre Operator:

BEDINGUNG ? WAHR : FALSCH;

http://perldoc.perl.org/perlop.html#Conditional-Op...

Analag dazu das if:

if ( BEDINGUNG ) {
WAHR
}
else {
FALSCH
}

[edit] PS: wenn Du schon Fehlermeldungen erwähnst, dann solltest Du die bitte auch nennen!

edit2:
es kann sein, dass, wenn kein Argumente mitgegeben wurden, Perl meckert, weil $ARGV[0] und $ARGV[1] (generell @ARGV) uninitialisiert sein dürfte. Das kannst Du so abfangen:

Code (perl): (dl )
1
2
my $init_popsize = defined $ARGV[0] ? $ARGV[0] - 1 : 10 ; # wenn keine Angabe dann 10 annehmen
my $maxtime = defined $ARGV[1] ? $ARGV[1] : 10; # wenn keine angabe dann 10 Durchläufe machen

meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
Linuxer
 2008-01-14 12:36
#104686 #104686
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
Linuxer+2008-01-13 18:46:06--
es kann sein, dass, wenn kein Argumente mitgegeben wurden, Perl meckert, weil $ARGV[0] und $ARGV[1] (generell @ARGV) uninitialisiert sein dürfte. Das kannst Du so abfangen:

Code (perl): (dl )
1
2
my $init_popsize = defined $ARGV[0] ? $ARGV[0] - 1 : 10 ; # wenn keine Angabe dann 10 annehmen
my $maxtime = defined $ARGV[1] ? $ARGV[1] : 10; # wenn keine angabe dann 10 Durchläufe machen


Alternativ ginge wohl auch (Achtung: hier fällt dann die "-1" bei $init_popsize weg):
Code (perl): (dl )
1
2
my $init_popsize = shift @ARGV  || 10 ; # wenn keine Angabe dann 10 annehmen
my $maxtime = shift @ARGV || 10; # wenn keine angabe dann 10 Durchläufe machen


EDIT: Eine übergebene 0 wird als FALSE gewertet und somit die 10 zugewiesen! Siehe die nächsten 2 Beiträge.
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
renee
 2008-01-14 12:47
#104689 #104689
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
@Linuxer: dann wird aber nicht auf definiertheit überprüft. Bei Dir würde eine "0" in $ARGV[0] durch eine "10" ersetzt werden...
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
Linuxer
 2008-01-14 13:25
#104695 #104695
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
renee+2008-01-14 11:47:53--
@Linuxer: dann wird aber nicht auf definiertheit überprüft. Bei Dir würde eine "0" in $ARGV[0] durch eine "10" ersetzt werden...

Hast natürlich recht. Dieses Sachverhalt "vergeß" ich durchaus schon mal.

Meist verwende ich das "shift @ARGV || 10;" in einem Kontext, wo ich keine 0 übergeben muss. Von daher hat mich meine Vergeßlichkeit (jedenfalls in den letzten Monaten) nicht dafür bestraft ;o)
Aber recht hast Du. Um sauber zu bleiben, sollte die defined() Variante genutzt werden.
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
renee
 2008-01-14 13:34
#104697 #104697
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
... dann einfach auf Perl 5.10 umstellen, dort geht dann
Code (perl): (dl )
my $foo = shift @array // 10;


// ist der "defined-or"-Operator und da "0" definiert ist, wird die "10" nicht zugewiesen.
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
<< |< 1 2 >| >> 12 Einträge, 2 Seiten



View all threads created 2008-01-12 17:22.