Perlのクロスライン比較

Perlのクロスライン比較

私は以下を持っていますfile

Name v1 v2 
Type1 ABC 32
Type1 DEF 44
Type1 XXX 45
Type2 ABC 78 
Type2 XXX 23 
Type3 DEF 22 
Type3 XXX 12 
Type4 ABC 55 
Type4 DEF 78 
Type5 ABC 99 
Type6 DEF 00

次の条件でファイルの一部のみを印刷しようとします。

  • たとえば、特定の名前がType1列に存在する場合は、そのファイル内のすべてのアイテムの印刷をスキップしたいと思います。XXXv1Type1
  • 与えられた名前の列に合計がType4ある場合は、小さい値を持つ行だけを印刷したいと思います。ABCDEFv1v2
  • or と同じ名前の場合Type5orType6だけがある場合はABC印刷DEFしたいと思います。

私は何をすべきですか?ファイルを配列として読み取ることができますが、複数の行から特定の列を取得する方法がわかりません。

ベストアンサー1

これに必要なツールはハッシュです。これは、キーと値のペアを格納するPerlの方法です。特に、最も低い値または発生項目を「見つける」ことができるように、データをハッシュとして前処理する必要がありますXXX

幸いなことに、3番目の条件は2番目の条件のサブセットのように見えます。最も低い値だけを印刷すると、1つしかないときは最も低い値が同じになります。

だから私はこれを行うことができます:

#!/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";
}

これは以下の結果を提供します(一部の診断結果が少ないため、Dumper必要でない場合は自由に破棄してください)。

Name v1 v2 
Type4 ABC 55
Type5 ABC 99
Type6 DEF 00

おすすめ記事