http://www.perlmonks.org?node_id=356853

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

I am trying to fix an error I get when working on an array. The code below has an array with (8) 1s, (6) 2s, (2) 3s, (5) 4s, and (4) 5s. I need to figure this out in order for me to proceed to the next part of my program. If you notice the output below the code I am printing (9) 1s when it should only be 8. Does anyone in the Monastery have any thoughts?
@ID = (1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,4,4,4,4,4,5,5,5,5); $evr_id = 0; $count = 1; $flag = 0; $processed = 1; print "\n"; foreach $a (@ID) { if($flag == 0) { $evr_id = $a; print "$processed) $evr_id-$count\n"; $flag = 1; $count++; }elsif($evr_id != $a) { print "$processed) $evr_id-$count\n\n"; $count = 1; $evr_id = $a; $flag = 0; }else{ print "$processed) $a-$count\n"; $count++; } if(scalar(@ID) == $processed) { print $processed + 1 . ") $a-$count\n"; } $processed++; } OUTPUT: 1) 1-1 2) 1-2 3) 1-3 4) 1-4 5) 1-5 6) 1-6 7) 1-7 8) 1-8 9) 1-9 10) 2-1 11) 2-2 12) 2-3 13) 2-4 14) 2-5 15) 2-6 16) 3-1 17) 3-2 18) 4-1 19) 4-2 20) 4-3 21) 4-4 22) 4-5 23) 5-1 24) 5-2 25) 5-3 26) 5-4

Replies are listed 'Best First'.
Re: Problems with looping through an array
by gmax (Abbot) on May 27, 2004 at 10:34 UTC

    Use a hash to get a count of each unique item.

    #!/usr/bin/perl -w use strict; use Data::Dumper; my @ID = (1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,4,4,4,4,4,5,5,5,5); # # count # my %items =(); $items{$_}++ for @ID; print "$_ => $items{$_}\n" for sort keys %items; # # detail # %items =(); my $count =0; push @{$items{$_}}, $count++ for @ID; print Data::Dumper->Dump([ \%items], ['items']); __END__ output: 1 => 8 2 => 6 3 => 2 4 => 5 5 => 4 $items = { '4' => [ 16, 17, 18, 19, 20 ], '1' => [ 0, 1, 2, 3, 4, 5, 6, 7 ], '3' => [ 14, 15 ], '2' => [ 8, 9, 10, 11, 12, 13 ], '5' => [ 21, 22, 23, 24 ] };

    (update) Instead of Data::Dumper, you could also get your details this way:

    print "$_ => (@{$items{$_}})\n" for sort keys %items ; __END__ 1 => (0 1 2 3 4 5 6 7) 2 => (8 9 10 11 12 13) 3 => (14 15) 4 => (16 17 18 19 20) 5 => (21 22 23 24)

    See also Perl Idioms Explained - keys %{{map{$_=>1}@list}} in Tutorials to see how the hash mechanism works.

    As for the error in your code, this node could be of help.

     _  _ _  _  
    (_|| | |(_|><
     _|   
    
Re: Problems with looping through an array
by davis (Vicar) on May 27, 2004 at 10:33 UTC

    I'm not too sure what your code is supposed to be doing. It looks a bit like you're trying to count the number of times a particular value occurs in an array. The normal way of doing this is to use a hash:

    #!/usr/bin/perl use warnings; use strict; my @ID = qw/1 1 1 1 1 1 1 2 2 2 2 2 3 3 4 4 4 4 5 5 5 5 6/; my %counts; foreach my $id (@ID) { $counts{$id}++; } while(my ($num, $count) = each(%counts)) { print "$num : $count\n"; }

    But you might be trying to do something more complicated than that. Some more explanation of what you're trying to achieve would help


    davis
    It's not easy to juggle a pregnant wife and a troubled child, but somehow I managed to fit in eight hours of TV a day.
Re: Problems with looping through an array
by antirice (Priest) on May 27, 2004 at 10:45 UTC

    Wow, that's some funky code there. Rearrange it a little and you get what you wanted:

    @ID = (1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,4,4,4,4,4,5,5,5,5); $evr_id = undef; $count = 0; $flag = 0; $processed = 1; print "\n"; foreach $a (@ID) { if ($evr_id != $a) { $count = 1; $evr_id = $a; print "\n$processed) $a-$count\n"; } else { $count++; print "$processed) $a-$count\n"; } $processed++; }

    If you just want counts, then you probably want the other two solutions. If you're looking for series, then this would probably be preferred.

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1

Re: Problems with looping through an array
by hv (Prior) on May 27, 2004 at 11:48 UTC

    When you encounter a new value:

    elsif($evr_id != $a) { print "$processed) $evr_id-$count\n\n"; $count = 1; ...
    it s correct to initialise the count to 1, because you've just seen the first example of the new value.

    When you first enter the loop, though, you haven't yet seen the first example of the initial number. So you should be initialising $count to 0 before the loop, not 1.

    Hugo