[geklärt] PERL WARNING: Use of uninitialized value within @d in string at ...

Begonnen von TomLee, 23 Dezember 2021, 12:04:46

Vorheriges Thema - Nächstes Thema

TomLee

Hallo,

kann mich noch weitere zwei Tage mit beschäftigen, ich zweifle mittlerweile daran irgendwann selbst drauf zu kommen warum es zu der Meldung kommt ?

Mach ich wirklich noch was falsch ?
Kann es vlt. am Ende von der verwendeten Perl Version abhängig sein ?

{
  my @d = qw(bli bla blub);;
  my %c;;
  for my $i (1..@d) {
  $c{$i}="$d[$i]";;
  }
  print join(" ",sort keys %c),"\n";;
}

{
  my @d = qw(bli bla blub);;
  my %c;;
  for (my $i = 1;;$i <= @d;;$i++ ) {
  $c{$i}="$d[$i]";;
  }
  print join(" ",sort keys %c),"\n";;
}


2021.12.23 11:57:46 1: PERL WARNING: Use of uninitialized value within @d in string at (eval 33059) line 1.
2021.12.23 11:57:46 3: eval: {   my @d = qw(bli bal blub);   my %c;   for my $i (1..@d) {   $c{$i}="$d[$i]";   }   print join(" ",sort keys %c),"\n"; }
1 2 3
2021.12.23 11:58:00 1: PERL WARNING: Use of uninitialized value within @d in string at (eval 33086) line 1.
2021.12.23 11:58:00 3: eval: {   my @d = qw(bli bal blub);   my %c;   for (my $i = 1;$i <= @d;$i++ ) {   $c{$i}="$d[$i]";   }   print join(" ",sort keys %c),"\n"; }
1 2 3


Gruß

Thomas

Beta-User

Vermutlich liegt es daran, dass die Zählweise innerhalb eines Array etwas anders ist als man das vermutet: Das erste Element ist "0", nicht "1"...
Statt
for my $i (1..@d) {

sollte es m.E. heißen:
for my $i (0..@d-1) {
Das mit "@d-1" ist eigentlich auch eine etwas "schmutzige" Schreibweise, ganz korrekt sollte sein:
for my $i (0..$#arr) {
https://stackoverflow.com/questions/7406807/find-size-of-an-array-in-perl#comment92844211_7406807
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

TomLee

Zitatfor my $i (0..$#arr) {

Das mag ich aber nicht, ich möchte das der key bei 1 beginnt und 0..$#arr zählt wie du sagst von 0 bis 9.

Ergebnis wäre also 0 1 2, ich will wie gezeigt 1 2 3.

Christoph Morrison

Dein Code produziert folgendes:


# @d
$VAR1 = [
          'bli',
          'bla',
          'blub'
        ];

# %c
$VAR1 = {
          '1' => 'bla',
          '2' => 'blub',
          '3' => ''
        };



Warum?
$d[0] = bli
$d[1] = bla
$d[2] = blubb
$d[3] = ''


Du fängst bei der Iteration in for mit 1, nicht mit 0 an. Ergo: Du greifst auf einen nicht definierten Schlüssel $d[3] zu.

Beispiellösung:

use Data::Dumper;
use feature 'say';

my @d = qw(bli bla blub);

my ($i, %c);
for my $v (@d) {
    $i++;
    $c{$i} = $v;
}

say Dumper(\%c);


Ergibt:

$VAR1 = {
          '1' => 'bli',
          '3' => 'blub',
          '2' => 'bla'
        };

TomLee

Christoph hat mich verstanden, Danke für das Beispiel/erklären.

Beta-User

Zitat von: TomLee am 23 Dezember 2021, 12:23:11
Das mag ich aber nicht, ich möchte das der key bei 1 beginnt und 0..$#arr zählt wie du sagst von 0 bis 9.

Ergebnis wäre also 0 1 2, ich will wie gezeigt 1 2 3.
Na ja, um das vollständig zu machen:
Eine weitere Variante wäre, dann den Array-Pointer einfach entsprechend zu reduzieren:
  for my $i (1..@d) {
  $c{$i}="$d[$i-1]";;
  }

Oder den Hash-Pointer zu manipulieren:
  for my $i (0..$#d) {
  $c{$i+1}="$d[$i-1]";;
  }
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Christoph Morrison

Zitat von: TomLee am 23 Dezember 2021, 12:28:08
Christoph hat mich verstanden, Danke für das Beispiel/erklären.

Die Antwort von Beta-User ist ja auch nicht falsch, kommt halt darauf an, wo du zu zählen anfängst / anfangen willst.
Dein Fehler ist übrigens ein echter Klassiker.

TomLee

ZitatNa ja, um das vollständig zu machen:
Eine weitere Variante wäre, dann den Array-Pointer einfach entsprechend zu reduzieren:

Super  ::), erst hab ich goar nix und jetzt muss man sich für eine von drei Varianten entschliessen  ;D. Danke.

Christoph Morrison

Zitat von: TomLee am 23 Dezember 2021, 12:47:55
Super  ::), erst hab ich goar nix und jetzt muss man sich für eine von drei Varianten entschliessen  ;D. Danke.

Und zwei davon kann man kaum lesen ;-)

Willkommen in der Perl-Welt.

Beta-User

Zitat von: Christoph Morrison am 23 Dezember 2021, 13:51:52
Und zwei davon kann man kaum lesen ;-)

Willkommen in der Perl-Welt.
...wir könnten noch $i durch $_ ersetzen und versuchen ein map zu basteln...

Ansonsten wäre es vermutlich sinnvoll einige Quotes wegzulassen und sauberer einzurücken.

*duckundweg*
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

TomLee

Nochmal.

Hab mein Ziel jetzt erreicht, wie würdet ihr das machen ?

{
    my @d = qw(bli bla blub);;
    my @e = qw(Honk Monk Zonk);;
    my ($i, %c);;
    for my $v (@d) {
    $i++;;
    $c{$i} = $v;;
    }
    $i= keys %c;;
    for my $w (@e) {
    $i++;;
    $c{$i} = 'du '.$w;;
    }   
    print join(" ",sort values %c),"\n";;
}

bla bli blub du Honk du Monk du Zonk


TomLee

Und eine Frage hätte ich noch bezüglich der Rückgabe der Anzahl mit keys %irgendwas und @irgendwas, wenn man damit rechnen wollte klappt das problemlos, aber wäre es nicht korrekter das ganze dann in scalar() zu stecken, auch in dem Code jetzt ?

Christoph Morrison

print join(" ",sort values %c),"\n";;

Warum baust du dir erst einen numerischen Index (1..x), sortierst aber dann nach den Values im Hash?

TomLee

Das ist nur für mich gewesen zum nachvollziehen.

Ich will nur den Hash, sieh dir hier in setList den pct slider an, den vorderen Teil hab ich schon dynamisch und den hinteren Teil, iVm. mit diesem setter jetzt.

Ich hab das bis jetzt aber noch nicht eingebaut in setList und getestet, mach später erst.

TomLee

Mit map hab ich mich eben kurz beschäftigt, sieht bei mir, nach zwei-drei Tests, so aussehen:

{
my @d = qw(bli bla blub);;
my @e = qw(Honk Monk Zonk);;
my ($i, %c);;map {$i++;;$c{$i} = $_;;} (@d) ;;
$i= keys %c;;
map {$i++;;$c{$i} = 'du '.$_;;} (@e);;
}


Und auch hier (mit map) die Frage, wie ihr es machen würdet ?

Beta-User

...eher gar nicht mit map. Ging da nur um die Frage, wie man es noch unleserlicher notieren könnte...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

TomLee

Kann ich mangels Erfahrung ja nicht beurteilen, wenn ich mir den fertigen Code anschaue empfinde ich die map-Variante als angenehm und man spart sich noch die Definition einer Variable.


{
my @d = split(/,/,ReadingsVal($NAME,'speech_cmnd','none'));
my @e = split(/,/,ReadingsVal($NAME,'zones','none'));
my ($i, %pct2cmd);
    for my $v (@d) {$i++;$pct2cmd{$i} = $v;}
$i= keys %pct2cmd;
    for my $w (@e) {$i++;$pct2cmd{$i} = 'zone '.$w;};
my $cmd = $pct2cmd{$EVTPART1};
    return if !$cmd;
    return fhem("set $NAME !$cmd;setreading $NAME pct $EVTPART1");}

{
my @d = split(/,/,ReadingsVal($NAME,'speech_cmnd','none'));
my @e = split(/,/,ReadingsVal($NAME,'zones','none'));
my ($i,%pct2cmd);
    map {$i++;$pct2cmd{$i} = $_;} (@d);
$i= keys %pct2cmd;
    map {$i++;$pct2cmd{$i} = 'zone '.$_;} (@e);
my $cmd = $pct2cmd{$EVTPART1};
    return if !$cmd;
    return fhem("set $NAME $cmd;setreading $NAME pct $EVTPART1");
}

Christoph Morrison


TomLee

Das sind die Rückgabewerte des pct-slider, hab ich in #13 verlinkt.

TomLee

Hier meine fertige Lösung des pct-setter die bisher nach mehrerem testen problemlos klappt.