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

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

Hi Monks!
I am combining the elements of the array here on my code sample to get the unique one to my report, but what is happening is that I am loosing the negative values that is part of the unique array, I can't understand why it is happening, can someone help with that?
Just one more question, how would I get my results in alphabetic order, just in case someone has done that before. Here is the code:

#!/usr/bin/perl use strict; use warnings; use CGI::Carp qw(fatalsToBrowser); use CGI ':standard'; use Data::Dumper; my $test_array_ref = [ [ 'Amber Benedit C', '23455443', '2008-01-11', 'X', '11', '0', '7.00', ' ', '2', '2', '3', ' ', '-2.0', ' ', ' ', ' ', ' ', ' ', ' ', '3.0', '2008', '1112399' ], [ 'Amy Israel D', '22345666', '2008-03-04', 'X', '999', '0', '8.00', ' ', '0', '2', '0', ' ', '-5.00', ' ', ' ', ' ', ' ', ' ', ' ', '2.0', '2008', '1112399' ], [ 'Auser Ferro', '987778999', '2008-11-30', 'W', '200', '0', '0', ' ', '1', '2', '4', ' ', '-5.00', ' ', ' ', ' ', ' ', ' ', ' ', '2.0', '2008', '1112399' ], [ 'Auser Ferro', '987778999', '2008-11-30', 'W', '888', '0', '0', ' ', '1', '2', '4', ' ', '-5.00', ' ', ' ', ' ', ' ', ' ', ' ', '2.0', '2008', '1112399' ], [ 'Yuong John', '22357790', '2008-03-27', 'W', '50', '0', '4.00', ' ', '4', '2', '3', ' ', '0', ' ', ' ', ' ', ' ', ' ', ' ', '3.0', '2008', '1112399' ], [ 'Zilda Mil', '88997665', '2008-05-12', 'W', '999', '0', '4.00', ' ', '0', '2', '3', ' ', '0', ' ', ' ', ' ', ' ', ' ', ' ', '14.0', '2008', '1112399' ], [ 'Zilda Mil', '88997665', '2008-05-12', 'X', '999', '0', '4.00', ' ', '1', '2', '3', ' ', '-8.00', ' ', ' ', ' ', ' ', ' ', ' ', '9.0', '2008', '1112399' ] ]; ## TEST FOR UNIQUE VALUES # Group arrays by account number + higher elements in the array my $acc_num = {}; for my $aref (@$test_array_ref) { my $uniq_key = $aref->[0]; push @{$acc_num->{$uniq_key}}, $aref; } my $all_dta_acc_num = []; for my $aref_acc_num (values %$acc_num) { push @$all_dta_acc_num, my $tmp = []; for my $aref (@$aref_acc_num) { for my $i (0..1) { $tmp->[$i] = $aref->[$i]; } for my $i (2..$#$aref) { $tmp->[$i] = '0' unless defined $tmp->[$i]; # for 'use war +nings' # Need to check for numeric or string values here::: if($tmp->[$i]=~m/^[+-]?\d+$/){ $tmp->[$i] = $aref->[$i] if $aref->[$i] gt $tmp->[$i]; #}elsif($tmp->[$i]=~m/^[+-]?\w+$/){ #$tmp->[$i] = $aref->[$i] if $aref->[$i] gt $tmp->[$i]; }else{ $tmp->[$i] = $aref->[$i] if $aref->[$i] gt $tmp->[$i]; } # End checking for numeric or string values. } } } print Dumper $all_dta_acc_num;


Thank you!

Replies are listed 'Best First'.
Re: Loosing Negative Values in Array Ref
by Thelonius (Priest) on Jun 03, 2009 at 13:41 UTC
    You have
    $tmp->[$i] = '0' unless defined $tmp->[$i]; ... $tmp->[$i] = $aref->[$i] if $aref->[$i] gt $tmp->[$i];
    Since a "-" is lt "0", you're never going to be seeing negative numbers.

    To get the array in alphabetical order, use sort. You could sort it after you create it, or you can create it in alphabetical order by changing

    for my $aref_acc_num (values %$acc_num) {
    to
    for my $aref_acc_key (sort keys %$acc_num) { my $aref_acc_num = $acc_num->{$aref_acc_key};
        By that point in the code, there are no negatives anyway
        No.

        Here, I think this is what you want:

        for my $aref_acc_num (sort { $a->[0] cmp $b->[0] } values %$acc_num) { push @$all_dta_acc_num, my $tmp = []; for my $aref (@$aref_acc_num) { for my $i (0..1) { $tmp->[$i] = $aref->[$i]; } for my $i (2..$#$aref) { if (!defined($tmp->[$i])) { $tmp->[$i] = $aref->[$i]; } elsif ($tmp->[$i]=~m/^[+-]?\d+$/) { #numeric $tmp->[$i] = $aref->[$i] if $aref->[$i] > $tmp->[$i]; } else { $tmp->[$i] = $aref->[$i] if $aref->[$i] gt $tmp->[$i]; } } } }
        But how could I print my results and get for this particular element as an example this result:
        [ 'Auser Ferro', '987778999', '2008-11-30', 'W', '888', '0', '0', '0', '1', '2', '4', '0', '-5.00', '0', '0', '0', '0', '0', '0', '2.0', '2008', '1112399' ],

        Notice the "-5.00". Thats what I am looking for.
      Thats true, how to keep the same logic and still check having these negative values in the array?
        Aside from the numeric vs string issue. Numeric "zero" is greater than "-5"! So maybe what you need here is to use absolute vale abs() when comparing things so that abs(-5) is > 0.?
Re: Loosing Negative Values in Array Ref
by Anonymous Monk on Jun 03, 2009 at 13:24 UTC
    I can't understand why it is happening, can someone help with that?

    If you add

    warn $tmp->[$i] = '0'; # Need to check for numeric or string values here:::
    you'll never see any negative numbers. This means code before is problem, but what is it supposed to do?
      To avoid duplicated records I am using this code to combine them, getting a unique account number (second element) and the greatest values comparing them if they are equal, if you run the code you will see it better, but how could I still display the negatives?
        getting a unique account number (second element)
        Your code my $uniq_key = $aref->[0]; is actually using the name, not the account number.
Re: Loosing Negative Values in Array Ref
by Marshall (Canon) on Jun 04, 2009 at 15:23 UTC
    I took at a stab at coding this thing. I don't know if this helps or not, you may find the function anyCompare useful...Could be some problems with this code...Dunno..its early in the morning here...
    my $test_array_ref = [ [ 'Amber Benedit C', '23455443', '2008-01-11', 'X',.... ....... like in your post........ ]; my %accountNames =(); foreach my $record_ref (@$test_array_ref) { my ($name, @new_data) = @$record_ref; if (exists $accountNames{$name}) { my @current_data = @{$accountNames{$name}}; my $i =0; foreach my $new_thing (@new_data) { if (anyCompare($new_thing,$current_data[$i])>0) {$current_data[$i]= $new_thing}; $i++; } @{$accountNames{$name}}=@current_data; } else { $accountNames{$name} = [@new_data]; } } foreach my $name (sort keys %accountNames) { print "NAME=$name\n"; print join ("\n", map{/^\s*$/ ? '""' : $_} @{$accountNames{$name}}),"\n"; print "\n"; } sub anyCompare #returns <0,0,>0 like normal <=> or cmp { my ($a,$b) = @_; if ( isNumeric($a) && isNumeric($b) ) {return $a <=> $b} return ($a cmp $b) } sub isNumeric #returns True/False { my $string = shift; my $isNumeric = ($string =~ m/^[-+]*\d+(\.\d+)?$/); return $isNumeric; } __END__ prints: NAME=Amber Benedit C 23455443 2008-01-11 X 11 0 7.00 "" 2 2 3 "" -2.0 "" "" "" "" "" "" 3.0 2008 1112399 NAME=Amy Israel D 22345666 2008-03-04 X 999 0 8.00 "" 0 2 0 "" -5.00 "" "" "" "" "" "" 2.0 2008 1112399 NAME=Auser Ferro 987778999 2008-11-30 W 888 0 0 "" 1 2 4 "" -5.00 "" "" "" "" "" "" 2.0 2008 1112399 NAME=Yuong John 22357790 2008-03-27 W 50 0 4.00 "" 4 2 3 "" 0 "" "" "" "" "" "" 3.0 2008 1112399 NAME=Zilda Mil 88997665 2008-05-12 X 999 0 4.00 "" 1 2 3 "" 0 "" "" "" "" "" "" 14.0 2008 1112399