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

I am missing something in this snippet... it claims every label only has a single record and then deletes it. I know however that there are SOME duplicates in the list of tapes after looking through it carefully. Did I construct my HoA wrong ... need outside viewpoint ... looking too long at the code any help appreciated.
209 sub hash_tapes (@) { 210 211 my @tapes = @_; 212 my %Tape_Cat =(); 213 214 foreach my $tape (@tapes) { 215 my ( $label, $protection, $location, $pool ) = @{$tape +}; 216 push @{ $Tape_Cat{$label} }, [ $protection, $location, + $pool ]; 217 } 218 219 # Get rid of non-duplicates 220 my $count = 0; 221 foreach my $tape (@tapes) { 222 my ($label,$protection,$location,$pool) = @{$tape}; 223 if ( @{$Tape_Cat{ $label}} < 2 ) { 224 print "Deleting ". $label. 225 "Because it has ".@{$Tape_Cat{ $label }}. 226 " record(s)\n"; 227 $count++; 228 delete $Tape_Cat{$label} 229 } 230 } 231 232 my @keys = keys %Tape_Cat; 233 print "Deleted $count keys, keys: @keys\n"; 234 return \%Tape_Cat; 235 }

Replies are listed 'Best First'.
Re: Hmmm... HoA help ...
by pg (Canon) on Nov 29, 2002 at 06:32 UTC
    (Just a small suggestion, if you can remove those line numbers first before you post your code, it will greatly benefit fellow monks, who might help you test :-) I tested with,
    hash_tapes(["t1", "pr1", "l1", "po1"], ["t2", "pr2", "l2", "po2"], ["t3", "pr3", "l3", "po3"], ["t1", "pr2", "l2", "po2"]);
    and it seems fine for this case. It deleted t2, t3, but left t1 there. How did you test it?

      %Tape_Cat should be hash whose keys are the tape labels Each key contains an array of refs. Each ref in this array is anarray ref containing Protection, Location, and Pool

      Looks like: %Tape_Cat->Label->Record1 { Protection, Location, Pool } |->Record2 { Protection, Location, Pool } . . |->Recordn {Protection, Location, Pool } I want to determine the value n and elminate those tapelabels with onl +y one record.

      I think your suggestion will place only one record , whichever is found last in %Tape_Cat. Am I missing the point?

(bbfu) Re: Hmmm... HoA help ...
by bbfu (Curate) on Nov 29, 2002 at 06:51 UTC

    The problem is line 223. You've got your condition backwards.

    # *** Incorrect **** if ( @{$Tape_Cat{ $label}} < 2 ) { # Executes if there is only 1 (or 0) instances of $label } # *** Correct *** if ( @{$Tape_Cat{ $label}} > 1 ) { # Executes if there is more than 1 (ie, any duplicates) }

    bbfu
    Black flowers blossum
    Fearless on my breath

      However I want to delete ONLY those records that are singletons. I want to generate a list of tapes having more than one record. The problem is that every tape ... even ones I know have duplicate records are being treated as singletons.

        Oh, heh. Delete non-duplicates. Right, sorry. :)

        Anyway, what you have posted works fine (which is what I thought initially, before I got confused about which you were wanting to remove).

        [johnsca@CORY tmp]$ cat tst.pl #!/usr/bin/perl my @Tapes = ( ['Label 1', 'p', 'l', 'P'], ['Label 1', 'p', 'l', 'P'], # Duplicate ['Label 2', 'p', 'l', 'P'], ['Label 3', 'p', 'l', 'P'], ); hash_tapes(@Tapes); sub hash_tapes (@) { my @tapes = @_; my %Tape_Cat =(); foreach my $tape (@tapes) { my ( $label, $protection, $location, $pool ) = @{$tape}; push @{ $Tape_Cat{$label} }, [ $protection, $location, $pool ] +; } # Get rid of non-duplicates my $count = 0; foreach my $tape (@tapes) { my ($label,$protection,$location,$pool) = @{$tape}; if ( @{$Tape_Cat{ $label}} < 2 ) { print "Deleting ". $label. "Because it has ".@{$Tape_Cat{ $label }}. " record(s)\n"; $count++; delete $Tape_Cat{$label} } } my @keys = keys %Tape_Cat; print "Deleted $count keys, keys: @keys\n"; return \%Tape_Cat; } [johnsca@CORY tmp]$ ./tst.pl Deleting Label 2Because it has 1 record(s) Deleting Label 3Because it has 1 record(s) Deleted 2 keys, keys: Label 1

        Correct, no? You should probably double-check the data that this function is actually getting. Use Data::Dumper at the begining of the function, or the built-in perl debugger. Update: If the data is coming from an outside source, check for strange things like leading or trailing newlines or linebreaks, or non-printable characters, or such.

        Good luck. :)

        bbfu
        Black flowers blossum
        Fearless on my breath