The tool you need for this is hashes - which are perl's way of storing key-value pairs. Specifically - we need to preprocess your data into a hash, so we can 'look up' places where lowest values or XXX
is present.
Fortunately - your third condition looks like a subset of your second - if you're just printing the lowest value, the lowest value when there's only one, is the same.
So I'd probably do it something like this:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
#read header line, because we don't want to process it;
#note - diamond operators are 'magic' file handles.
#they read either piped input on STDIN, or
#open/read files specified on command line.
#this is almost exactly like how sed/grep work.
my $header_line = <>;
#turn the rest of our intput into an array of arrays, split on whitespace/linefeeds.
my @lines = map { [split] } <>;
#print for diag
print Dumper \@lines;
#this hash tracks if we've 'seen' an XXX
my %skip_type;
#this hash tracks the lowest V2 value.
my %lowest_v2_for;
foreach my $record (@lines) {
#we could work with $record ->[0], etc.
#this is because I think it's more readable this way.
my ( $type, $v1, $v2 ) = @$record;
#find all the lines with "XXX" - store in a hash.
if ( $v1 eq "XXX" ) {
$skip_type{$type}++;
}
#check if this v2 is the lowest for this particular type.
#make a note if it is.
if ( not defined $lowest_v2_for{$type}
or $lowest_v2_for{$type} > $v2 )
{
$lowest_v2_for{$type} = $v2;
}
}
#print for diag - things we are skipping.
print Dumper \%skip_type;
print $header_line;
#run through our list again, testing the various conditions:
foreach my $record (@lines) {
my ( $type, $v1, $v2 ) = @$record;
#skip if it's got an XXX.
next if $skip_type{$type};
#skip if it isn't the lowest value
next if $lowest_v2_for{$type} < $v2;
#print otherwise.
print join( " ", @$record ), "\n";
}
This gives (less some diagnostic output from Dumper
which can be discarded freely if you don't want it):
Name v1 v2
Type4 ABC 55
Type5 ABC 99
Type6 DEF 00