my @names = qw(Kamel Schlange Hai);
$tmp{Kamel}{Schlange}{Hai}
1
2
3
4
5
6
7
8
entwicklung@ubuntu:~$ perl -MData::Dumper -le 'my @var = qw(Hund Katze Maus); my $hashref = {}; my $tmp = $hashref; for ( @var ) { $tmp->{$_} = {}; $tmp = $tmp->{$_} } print Dumper $hashref'
$VAR1 = {
'Hund' => {
'Katze' => {
'Maus' => {}
}
}
};
2011-06-21T06:50:26 reneeSo kommt man ohne eval und rekursive Funktion aus.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
my @var = ( [qw(Hund Katze Maus)], [qw(Hund Katze Ratte)], [qw(Hund Tiger Ratte)], [qw(Hund Tiger Maus)], ) my $hashref = {}; for my $arr ( @var ) { my $tmp = $hashref; for(@$arr) { $tmp->{$_} = {}; $tmp = $tmp->{$_} } } print Dumper $hashref;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
my @var = ( [qw(Hund Katze Maus)], [qw(Hund Katze Ratte)], [qw(Hund Tiger Ratte)], [qw(Hund Tiger Maus)], ) my $hashref = {}; for my $arr ( @var ) { my $tmp = $hashref; for(@$arr) { $tmp->{$_} = {} unless( exists $tmp->{$_} ); $tmp = $tmp->{$_} } } print Dumper $hashref;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
my @var = ( [qw(Hund Katze Maus)], [qw(Hund Katze Ratte)], [qw(Hund Tiger Ratte)], [qw(Hund Tiger Maus)], ); my $hashref = {}; for my $arr ( @var ) { my $tmp = \$hashref; $tmp = \$$tmp->{$_} for(@$arr); $$tmp={}; } print Dumper($hashref);
2011-06-21T07:46:36 topegBei deinem Code werden alte "Pfade" überschrieben.
man kann das mit einer Abfrage verhindern:
QuoteAber ich finde es ist besser die Autovivikation zu nutzen:
2011-06-21T07:52:09 shi8daoStimmt, habe ich auch gerade festgestellt (und if statt unless genommen).
2011-06-21T07:56:56 pq(wozu schreibe ich überhaupt wiki-artikel...? es dankt einem eh niemand
Quoteund es will doch jeder das rad neu erfinden, wie man sieht)
2011-06-21T07:55:10 pqweil ich keine Lust hatte? :-)wieso nicht einfach $tmp = $tmp->{$_} ||= {};
2011-06-21T06:35:16 shi8daoSpaeter muss ich durch alle Eintraege iterieren.
Wegen der Struktur bietet sich ja eine rekursive Funktion an, die sich selbst wieder aufruft, wenn ein Value ein Hash ist.
Benutze ich dazu am besten UNIVERSAL::isa($value, 'HASH')?
1 2 3 4
my $ref = ref $value; if ( $ref and $ref eq 'HASH' ) { eine_ebene_tiefer( $ref ); }
2011-06-21T06:53:32 reneeDa brauchst Du ref:Code (perl): (dl )1 2 3 4my $ref = ref $value; if ( $ref and $ref eq 'HASH' ) { eine_ebene_tiefer( $ref ); }
2011-06-21T06:35:16 shi8daoBaue ich mir da einen String zusammen und benutze eval? Das klaenge fuer mich evil ;-).
1 2 3 4 5 6 7 8 9
sub insert { my $hash = shift; #edit: werte wurden überschrieben: #$hash = $hash->{$_} = {} for @_; $hash = $hash->{$_} ||= {} for @_; return $hash; } insert(\%tmp, @names);
2011-06-21T06:35:16 shi8daoSpaeter muss ich durch alle Eintraege iterieren.
Wegen der Struktur bietet sich ja eine rekursive Funktion an, die sich selbst wieder aufruft, wenn ein Value ein Hash ist.
Benutze ich dazu am besten UNIVERSAL::isa($value, 'HASH')?
1 2 3 4 5 6 7 8 9 10
sub traverse { my $hash = shift; print "do something with: @_\n" if @_; return if not ref $hash or ref $hash ne 'HASH'; traverse($hash->{$_}, $_) for keys %$hash; } traverse(\%tmp);
2011-06-21T07:40:18 pqkomisch, das hat noch nieee einer gefragt ;-)
HashOfHashesAusArray
(habs aber eben nochmal editiert, die version hatte einen fehler im aufruf der funktion)
1 2 3 4
$tmp{Kamel}{Schlange}{Hering}{Hai} = 5; $tmp{Kamel}{Schlange}{Hering}{Huhn} = 7; $tmp{Katze}{Schlange}{Hering}{Huhn} = 9; $tmp{Katze}{Schlange}{Hering}{Hai} = 24;
1 2
print $tmp{Kamel}{Schlange}; # sollte jetzt 12 sein print $tmp{Katze}{Schlange}; # sollte jetzt 33 sein
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
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @var = ( ['Hund/Katze/Maus', 10], ['Hund/Katze/Ratte', 9], ['Hund/Katze/Hase', 8], ['Wolf/Katze/Maus', 7], ['Wolf/Katze/Ratte', 6], ['Wolf/Katze/Hase', 5], ['Hund/Tiger/Maus', 4], ['Hund/Tiger/Ratte', 3], ['Hund/Tiger/Hase', 2], ['Wolf/Tiger/Maus', 1], ); my $hashref = {}; for my $v ( @var ) { my $val=$v->[1]; my @arr=split('/',$v->[0]); my $tmp = \$hashref; for(@arr) { $$tmp->{summe}+=$val; $tmp = \$$tmp->{childs}->{$_}; } $$tmp->{summe}+=$val; } print Dumper($hashref); # zugriff: print "Summe Wolf/Katze = ".$hashref->{childs}->{Wolf}->{childs}->{Katze}->{summe}."\n";
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
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @var = ( ['Hund/Katze/Maus', 10], ['Hund/Katze/Igel', 9], ['Hund/Katze/Hase', 8], ['Wolf/Katze/Maus', 7], ['Wolf/Katze/Igel', 6], ['Wolf/Katze/Hase', 5], ['Hund/Tiger/Maus', 4], ['Hund/Tiger/Igel', 3], ['Hund/Tiger/Hase', 2], ['Wolf/Tiger/Maus', 1], ); my $hashref = {}; my $deep=[]; for my $v ( @var ) { my $val=$v->[1]; my @arr=split('/',$v->[0]); my $pos=0; my $tmp = \$hashref; for(@arr) { $$tmp->{summe}+=$val; push(@{$deep->[$pos]},$$tmp) if(!grep{$_ and $$tmp eq $_}@{$deep->[$pos]}); $tmp = \$$tmp->{childs}->{$_}; $pos++; } $$tmp->{summe}+=$val; push(@{$deep->[$pos]},$$tmp) if(!grep{$_ and $$tmp eq $_}@{$deep->[$pos]}); } #print "Summe Wolf/Katze = ".$hashref->{childs}->{Wolf}->{childs}->{Katze}->{summe}."\n"; #print Dumper($hashref); for my $pos (0..$#$deep) { print "POS($pos): "; print "$_->{summe}, " for(@{$deep->[$pos]}); print "\n"; }
2011-06-21T15:57:34 topegWillst du den Baum nachträglich noch durcharbeiten, so kannst du es so machen:
QuoteBedenke aber, dass das unter Umständen viel mehr Zeit braucht als die Nötigen Daten direkt bei der Erzeugung zu sammeln. Das hängt von der Tiefe und Umfang des Baumes zusammen.
2011-06-22T04:31:59 shi8daoIch fand es nützlich auswählen zu können ob nach dem Startkommando etwas ausgeführt wird. Es könnte sein, dass man nur bestimmte Teilbäume durchsuchen will, oder den Teilbaum mit einer eigenen Funktion und nicht mit traverse durch gehen will. Darum habe ich $cmd_start in ein if gepackt.Warum brauche ich die 1 am Ende von $cmd_start, nicht aber am Ende der beiden anderen Funktionen? Schlaegt sonst das elseif in traverse_deep fehl?