Hauptmenü

Index Array Zugriff

Begonnen von TomLee, 04 August 2020, 11:30:54

Vorheriges Thema - Nächstes Thema

TomLee

Hallo,

hab ich noch eine andere Möglichkeit außer List::MoreUtils zu verwenden um den Index eines bestimmten Listenelements zu erhalten ?

    use strict;
    use warnings;
    use 5.010;
    use List::MoreUtils qw(first_index);
     
    my @planets = ("1","2","3");
     
    say first_index { $_ eq '2' } @planets;

   1



Gruß

Thomas

ja es geht:

    use strict;
    use warnings;
    use 5.010;

     
    my @planets = ("1","2","3","4");
     
    my ($index) = grep { $planets[$_] eq '3' } (0 .. @planets-1);
   
   say defined $index ? $index : -1;

Damian

#1
Es ist immer systembelastend Index zu einem Inhalt zu finden, da man immer eine Schleife benutzen muss (auch wenn es nicht immer sichtbar ist).

Besser ist es an dieser Stelle mit einem Hash zu arbeiten, dessen Inhalt lässt ich mit einem Schlüssel (Text) zu indizieren.

Deine Frage gehört aber eher in die Perl-Ecke.

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

TomLee

Danke für den Hinweis Damian.

Das Beispiel mit dem Hash auf perlmaven hab ich noch nicht ganz verstanden, bin aber dran.

Damian

#3
Beim Array kommst du nur über einen numerischen Index an den Inhalt.

my @tier;
my @farbe;

$tier[0]="Katze";
$farbe[0]="grau";

Wenn du wissen willst, ob Katze dabei ist, dann musst du nach der Katze im Array @tier suchen.

Beim Hash kannst du das Wort "Katze" als Schlüsselwort nehmen;

my %farbe;

$farbe{Katze}="grau";

mit:

if (defined $farbe{Katze})

weißt du ob Katze dabei ist und mit

$farbe{Katze}

weißt du auch welche Farbe sie hat.

Nachteil vom hash ist, dass keine Reihenfolge im Gegensatz im Array gegeben ist. Zugriff auf Inhalt ist beim Hash langsamer als beim Array (ca. Faktor 2)

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

TomLee

War eigentlich letzte Woche dabei mich damit zu beschäftigen aus dem get des Calendar-Device einen Hash zu machen, um dann mit setreading Readings zu den letzten 5 Kalendereinträgen zu erstellen, dann bin ich aber über den Thread gestolpert und die Idee wieder verworfen.

Also dann doch über den Zugriff auf den Index eines Array.

Kann mir jemand sagen was ich bei dem return wenn es kein Element gibt falsch mache und das Reading nicht gelöscht wird ?

Im Kalender gibts dreI Einträge:
30.03.2021 15:00 Irgendwas anderes noch
31.03.2021 08:00 Noch was anderes
04.04.2021 17:00 Was ganz anderes


Im Reading t_004_summary steht dann
setstate ical_bla 2021-03-30 12:58:57 t_004_summary Deleted reading t_004_summary for device ical_bla


attr ical_bla userReadings t_001_summary:lastUpdate:.* {pk_ek($NAME)},\
t_002_summary:lastUpdate:.* {pk_zk($NAME)},\
t_003_summary:lastUpdate:.* {pk_dk($NAME)},\
t_004_summary:lastUpdate:.* {pk_vk($NAME)},\
t_005_summary:lastUpdate:.* {pk_fk($NAME)}

sub pk_ek {
my $NAME = shift;
my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
my @a= split("\n",$t);
return fhem('deletereading '.$NAME.' t_001_summary') if !defined($a[0]);
return $a[0];
}

sub pk_zk {
my $NAME = shift;
my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
my @a= split("\n",$t);
return fhem('deletereading '.$NAME.' t_002_summary') if !defined($a[1]);
return $a[1];
}

sub pk_dk {
my $NAME = shift;
my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
my @a= split("\n",$t);
return fhem('deletereading '.$NAME.' t_003_summary') if !defined($a[2]);
return $a[2];
}

sub pk_vk {
my $NAME = shift;
my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
my @a= split("\n",$t);
return fhem('deletereading '.$NAME.' t_004_summary') if !defined($a[3]);
return $a[3];
}

sub pk_fk {
my $NAME = shift;
my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
my @a= split("\n",$t);
return fhem('deletereading '.$NAME.' t_005_summary') if !defined($a[4]);
return $a[4];
}


Gruß

Thomas

Beta-User

Kann's grad nicht testen, vermute aber, dass immer ein Array mit 5 Elementen zurückgeliefert wird, wobei dann eben die Listenelemente nicht "undef" sind, sondern leer ("").

Ansonsten: Was spricht dagegen, immer dieselbe Funktion zu nehmen, und den Index mitzugeben?

sub pk_ek {
    my $NAME = shift;
    my $index = shift;
    my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
    my @a= split("\n",$t);
    my $ii = $index++;
    return fhem("deletereading $NAME t_00${ii}_summary") if !defined $a[$index] || $a[$index] eq '';
    return $a[$index];
}


(Generell gefällt mir das nicht so, weil 5x umständlich die Kalenderauswertung abgefragt wird. _Vermutlich_ wäre das effizienter mit einem notify auf die Aktualisierung des Kalenders zu lösen).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

TomLee

Zitatvermute aber, dass immer ein Array mit 5 Elementen zurückgeliefert wird,

Warum sollten das immer 5 Elemente sein, das get liefert doch immer nur die tatsächlich existierenden zurück, auch wenn ich 5 abrufe mit count=5

Oben hab ich gelogen tatsächlich sind es dann mit format:custom="$S" limit:from=0,count=5 die Beispiel-Einträge:

Irgendwas anderes noch
Lahr
Ostern


Zitat
Ansonsten: Was spricht dagegen, immer dieselbe Funktion zu nehmen, und den Index mitzugeben?
Nix, danke.

Klappt aber noch nicht und will jetzt was arbeiten, ich schaus mir später in Ruhe an.

attr ical_PensionRuthGmail userReadings t_001_summary:lastUpdate:.* {pk_k2r($NAME,'0')},\
t_002_summary:lastUpdate:.* {pk_k2r($NAME,'1')},\
t_003_summary:lastUpdate:.* {pk_k2r($NAME,'2')},\
t_004_summary:lastUpdate:.* {pk_k2r($NAME,'3')},\
t_005_summary:lastUpdate:.* {pk_k2r($NAME,'4')}


sub pk_k2r {
    my $NAME = shift;
    my $index = shift;
    my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
    my @a= split("\n",$t);
    my $ii = $index++;
    return fhem("deletereading $NAME t_00${$ii}_summary") if !defined $a[$index] || $a[$index] eq '';
    return $a[$index];
}


setstate ical_bla 2021-03-30 13:49:50 t_001_summary Lahr
setstate ical_bla 2021-03-30 13:49:50 t_002_summary Ostern
setstate ical_bla 2021-03-30 13:49:50 t_003_summary Error evaluating ical_bla userReading t_003_summary: Can't use string ("2") as a SCALAR ref while "strict refs" in use at ./FHEM/99_Abfall_Utils.pm line 60.\

setstate ical_bla 2021-03-30 13:49:50 t_004_summary Error evaluating ical_bla userReading t_004_summary: Can't use string ("3") as a SCALAR ref while "strict refs" in use at ./FHEM/99_Abfall_Utils.pm line 60.\

setstate ical_bla 2021-03-30 13:49:50 t_005_summary Error evaluating ical_bla userReading t_005_summary: Can't use string ("4") as a SCALAR ref while "strict refs" in use at ./FHEM/99_Abfall_Utils.pm line 60.\


Zitat_Vermutlich_ wäre das effizienter

Ein notify (zusätzliches Device) würd ich halt gern vermeiden wollen.

Beta-User

Sorry, aber beim drüber nachdenken ist
my $ii = $index++;vermutlich auch keine geglückte Abkürzung, das sollte eher so aussehen:
my $ii = $index + 1;Wird aber nichts an der Fehlermeldung ändern, da ist das Problem, dass CommandDeleteReading ein Array zurückgibt...

Daher insgesamt dann eher so:
sub pk_k2r {
    my $NAME = shift;
    my $index = shift;
    my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
    my @a= split("\n",$t);
    my $ii = $index + 1;
    if (!defined $a[$index] || $a[$index] eq '') {
        fhem("deletereading $NAME t_00${$ii}_summary");
        return;
    }
    return $a[$index];
}

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

TomLee

#8
Mit dem letzten Vorschlag kam die gleiche Fehlermeldung.

So klappts jetzt, auch wenn nur mit !defined $a[$index] geprüft wird oder auch nur auf $a[$index] eq ''.

Zitatsub pc_ce2r {
    my $NAME = shift;
    my $index = shift;
    my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
    my @a= split("\n",$t);
    my $ii = $index + 1;
    if (!defined $a[$index]) {
        fhem("deletereading $NAME t_00".$ii."_summary");
        return;
    }
    return $a[$index];
}

Bleibt bei mir aber irgendwie die Frage warum es nicht mit dem kurzen if klappt und wieder das gleiche (Deleted reading t_003_summary for device cal_example) wie bei meiner ersten Frage im Reading steht:

sub pc_ce2r {
    my $NAME = shift;
    my $index = shift;
    my $t = fhem('get '.$NAME.' events format:custom="$S" limit:from=0,count=5',1);
    my @a= split("\n",$t);
    my $ii = $index + 1;
    return fhem("deletereading $NAME t_00".$ii."_summary") if !defined $a[$index];
    return $a[$index];
}


edit:

Und warum du es mit einer skalaren Referenz ( ${$ii}) umsetzen willst/wolltest, hab ich auch noch nicht verstanden (bisher noch nicht mit beschäftigt), $ii ist doch einfach nur ein Scalar ? ? ?