Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

Updating A Hash Recursively

by Anonymous Monk
on Sep 05, 2005 at 05:31 UTC ( #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 (Sage) 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 (Hermit) on Sep 05, 2005 at 05:43 UTC


    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:


    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 (Abbot) 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 }
    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

    Quantum Mechanics: The dreams stuff is made of

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://489142]
Approved by GrandFather
Front-paged by broquaint
[ambrus]: Corion: two very hard things about presentations I should try to work on if I have twenty times as much free time as in real life are:
[Corion]: That's why I like HTML - it makes it relatively easy to resize stuff. Resizing with Powerpoint is much harder, or at least, I remember it being that way
[ambrus]: (a) good sans serif fonts optimized for slides in a projector with coverage of the symbols needed for mathematical formulas in a sans serif font matching the text font well, and
[ambrus]: (b) a good presentation system that lets the presenter quickly interactively edit the slides live during a presentation, to combine the advantages of blackboard and overhead slide styles in modern tech
[Corion]: Heh - in university, I cheated on (a) by doing blackboard presentations using chalk. But those were 2 hour presentations, not quick/essential/ reduced presentations where you want to show something quick
[ambrus]: (either on just one screen or two screens). this is necessary because
[ambrus]: overhead slide plus blackboard is inconvenient because the lighting conditions are different and they require separate areas you can't quickly repartition, and typing on keyboard is faster and more convenient than writing on a blackboard
[Corion]: (b) would be cool. I've thought about this doing Pod editing, and even simply regenerating/live updating the browser makes things much more interactive
[ambrus]: modern computers have way enough processing power to allow this, at least for geeks who are willing to spend a few weeks to learn a tricky new user interface like vim
[Corion]: ambrus: Well, for mathematical notation, I find blackboard much more convenient than a computer. But when inserting text or moving text around, the computer wins obviously

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (11)
As of 2017-09-26 10:18 GMT
Find Nodes?
    Voting Booth?
    During the recent solar eclipse, I:

    Results (293 votes). Check out past polls.