Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Updating A Hash Recursively

by Anonymous Monk
on Sep 05, 2005 at 05:31 UTC ( [id://489142]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Perlian, How come my code below doesn't update the original hash (%line)?
my %line = ('A' =>1, 'B' =>1, 'C' =>1); my @tojoin = qw (W X Y Z); foreach my $line ( keys %line ) { print "$line\n"; foreach my $tojoin ( @tojoin ) { my $nstr = $line.$tojoin; $line{$nstr} = 1; } last if ($line eq 'AYW'); }
Such that finally the %line will give:
A => 1, B => 1, C => 1, AW => 1, .... until AYW => 1

Replies are listed 'Best First'.
Re: Updating A Hash Recursively
by ChemBoy (Priest) on Sep 05, 2005 at 06:21 UTC

    Your code does update the original hash, it just doesn't do what you expected it to. In this case, it's because your expectation is at fault: when you call keys %line, you enumerate the keys of the hash at that point in time—that is to say, ("A","C","B") (note the disorder, since hashes don't preserve key order). You're wanting it to magically detect that you have added a key to the hash, and append that to the queue of keys to be processed, which is not in fact how Perl hashes work.

    All is not lost, however—you can achieve the desired effect much more economically with a little creative iteration:

    my @list = "A".."C"; my @tojoin = "W".."Z"; ITEM: for (my $i = 0; $i <= $#list; $i++) { for (map "$list[$i]$_", @tojoin) { push @list,$_; last ITEM if /^AYW$/; } } use Data::Dumper; print Dumper \@list;

    As an added benefit, this code produces the entries in the order you were probably expecting them in, and prevents annoying errors that would inevitably arise as side-effects of that problem.

    If, of course, you really do need the results in the hash form shown in the original post, you can achieve that by adding either of the following lines to the end of the code in place of the call to Dumper:

    @hash{@list} = (1) x @list; $hash{$_} = 1 for @list;



    If God had meant us to fly, he would *never* have given us the railroads.
        --Michael Flanders

      This is my code using recursive call.
      #!/usr/bin/perl use strict; use warnings; use Carp; my @lines = ('A', 'B', 'C'); my @tojoin = qw/X Y W/; my @new; sub closure; sub closure { my ($ary, $ret) = @_; if (length($ary->[0]) == 3) { return; } my @tmp; foreach (@$ary) { foreach my $to (@tojoin) { push @tmp, $_ . $to; } } push @$ret, @tmp; closure \@tmp, $ret; } closure \@lines, \@new; $, = ","; print @new;
Re: Updating A Hash Recursively
by GrandFather (Saint) on Sep 05, 2005 at 05:40 UTC

    Because the outer loop itterates over A-C and the inner loop itterates over W-Z so you generate:

    AW, AX, AY, AZ CW, CX, CY, CZ BW, BX, BY, BZ

    Perl is Huffman encoded by design.
Re: Updating A Hash Recursively
by gargle (Chaplain) on Sep 05, 2005 at 05:43 UTC

    Hi,

    I hope I understand the question.

    First, you do put things together :) However, as your print statement is in the block that does the joining you don't see the result. Put an extra foreach at the end to print out the result.

    Second, why that last if...? You iterate @tojoin over %item so that you'll end up only with:

    A
    B
    C
    AW
    AX
    AY
    AZ
    BW
    BX
    BY
    BZ
    CW
    CX
    CY
    CZ
    

    Is this what you want?

    #!/usr/bin/perl my %line = ('A' =>1, 'B' =>1, 'C' =>1); my @tojoin = qw (W X Y Z); foreach my $line ( keys %line ) { # print "$line\n"; foreach my $tojoin ( @tojoin ) { my $nstr = $line.$tojoin; $line{$nstr} = 1; } # last if ($line eq 'AYW'); } foreach my $line ( keys %line ) { print "$line\n"; }

    Of course, A, B and C stay in the original %item. You might need to delete them:

    ... foreach my $line ( keys %line ) { # print "$line\n"; delete $line{$line}; foreach my $tojoin ( @tojoin ) { my $nstr = $line.$tojoin; $line{$nstr} = 1; } # last if ($line eq 'AYW'); } ...
    --
    if ( 1 ) { $postman->ring() for (1..2); }
Re: Updating A Hash Recursively
by NetWallah (Canon) on Sep 05, 2005 at 06:11 UTC
    You need 3 levels of iteration to get 3 character keys. Something like this:
    my %line=qw(A 1 B 1 C 1); my @tojoin = qw (W X Y Z); for my $l(sort keys %line){ for my $k(@tojoin){ $line{qq($l$k$_)}=1 for @tojoin } }; print qq($_\n) for sort keys %line ; -- Output --- A AWW AWX AWY ...snip... B BWW BWX ...snip... BZZ C CWW ...snip... CZZ

         "Man cannot live by bread alone...
             He'd better have some goat cheese and wine to go with it!"

Re: Updating A Hash Recursively
by QM (Parson) on Sep 06, 2005 at 17:56 UTC
    glob to the rescue? glob can generate string combinations/permutations in many cases, depending on your needs.
    #!/your/perl/here use strict; use warnings; my %line = ('A' =>1, 'B' =>1, 'C' =>1); # last combination to emit (based on grep filter) my $last = 'AYW'; # build up strings for use with glob() my @line_keys = sort keys %line; my @tojoin = sort ('', qw (W X Y Z)); my $line_keys = join ',', @line_keys; my $tojoin = join ',', @tojoin; # alternation in glob uses '{string1,string2,...}' my $glob = '{' . join( '}{', $line_keys, $tojoin, $tojoin ) . '}'; # globbing @glob = glob $glob; # only keep strings shorter than $last, # or le $last my @glob = grep length($_) < length($last) || $_ le $last, @glob; # populate hash (easier ways???) @line{@glob} = (1) x @glob; # print results (note sort sub) foreach my $key (sort string_length keys %line) { print "$key => $line{$key}\n"; } # sort by length, then lexicographically sub string_length { length($a) <=> length($b) or $a cmp $b }
    yields
    A => 1 B => 1 C => 1 AW => 1 AX => 1 AY => 1 AZ => 1 BW => 1 BX => 1 BY => 1 BZ => 1 CW => 1 CX => 1 CY => 1 CZ => 1 AWW => 1 AWX => 1 AWY => 1 AWZ => 1 AXW => 1 AXX => 1 AXY => 1 AXZ => 1 AYW => 1

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://489142]
Approved by GrandFather
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-19 21:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found