しきい値より小さい数字で一番長い一連の行を印刷するには?

しきい値より小さい数字で一番長い一連の行を印刷するには?

私はPerlを学んでいますが、この問題を解決する方法がわかりません。

.txt次の形式のファイルがあります。

1 16.3346384
2 11.43483
3 1.19819
4 1.1113829
5 1.0953443
6 1.9458343
7 1.345645
8 1.3847385794
9 1.3534344
10 2.1117454
11 1.17465
12 1.4587485

最初の列には行番号のみが含まれており、ここでは興味がありませんが、2番目の列の値は関連部分です。

2番目の列に2.00未満の数値を持つ最長の連続行シーケンスを出力したいと思います。上記の例では3行から9行になり、出力は次のようになります。

1.19819
1.1113829
1.0953443
1.9458343
1.345645
1.3847385794
1.3534344

答え1

パール1行:

perl -ne '$n = (split)[1]; if ($n > 2) {if ($i > $max) {$longest=$cur; $cur=""; $max=$i}; $i=0} else {$cur .= $n . "\n"; $i++} END {print $i > $max ? $cur : $longest}' < file.txt

より良い読みやすさのための複数行:

perl -ne '
  $n = (split)[1];
  if ($n > 2) {
    if ($i > $max) {
      $longest=$cur;
      $cur="";
      $max=$i;
     }
     $i=0
  } else {
    $cur.= $n . "\n";
    $i++
  } 
  END {
    print $i > $max ? $cur : $longest
  }' < file.txt

ライナー1個awk

awk '$2 > 2 { if (i > max) {res=cur; cur=""; max=i} i=0} $2 < 2 {cur = cur $2 "\n"; i++} END {if (i > max) res=cur; printf res}' file.txt

複数行:

awk '
  $2 > 2 { 
    if (i > max) {
      res=cur
      cur=""
      max=i
    }
    i=0
  } 
  $2 < 2 {
    cur = cur $2 "\n"
    i++
  }
  END {
    if (i > max) res=cur
    printf res
  }' file.txt

答え2

これは決して些細なことではありません。完成したプログラムを提供することが他の人がプログラミング言語のトラブルシューティング方法を学ぶのに役立つかどうかについての議論もありますが、私はそれが利点を持っていると信じているので、次のプログラムを提案します(名前findlongestsequence.pl

#!/usr/bin/perl
use strict;
use Getopt::Long;

my $limit; my $infile;
GetOptions( 'limit=f' => \$limit, 'infile=s' => \$infile );

my $lineno=0; my $groupstart;
my $currlength=0; my $maxlength=0; my $ingroup=0;
my @columns; my @groupbuf; my @longestgroup;

if (! open(fileinput, '<', "$infile" )) {exit 1;};
while (<fileinput>)
{
    $lineno++;
    @columns = split(/\s+/,$_);

    if ( $ingroup == 0 && $columns[1]<$limit )
    {
        $ingroup=1;
        $groupstart=$lineno;
        @groupbuf=();
    }

    if ( $ingroup == 1 )
    {
        if ($columns[1]>=$limit )
        {
            $ingroup=0;
            $currlength=$lineno-$groupstart;
    
            if ( $currlength>$maxlength )
            {
                $maxlength=$currlength;
                @longestgroup=@groupbuf;
            }
        }
        else
        {
            push(@groupbuf,$columns[1]);
        }
    }
}
close(fileinput);

if ( $ingroup == 1 )
{
    $currlength=$groupstart-$lineno;
    if ( $currlength>$maxlength )
    {
        $maxlength=$currlength;
        @longestgroup=@groupbuf;
    }
}

print join("\n",@longestgroup),"\n";
exit 0;

このプログラムを呼び出すことができます。

./findlongestsequence.pl --infile input.txt --limit 2.0

まず、解釈されたコマンドライン引数を使用しますGetopt::Long

次にファイルを開き、1行ずつ読みます$lineno。各行は空白のある列に分割されます。

  • $limitプログラムが値が<(0)の行グループにないが$ingroup適切な行が見つかった場合は、現在そのグループ($ingroup1に設定)にあることを記録し、グループの開始と$groupstart開始のバッファリング列を保存します。 2つの配列値です@groupbuf
  • プログラムがそのようなグループ内にあるが現在の値が大きい場合は、$limitグループの尾を識別して長さを計算します。以前に記録された最長グループよりも長い場合、新しい最長グループの内容(@groupbuf)と長さ()がそれぞれにコピーされます。$currlength@longestgroup$maxlength

グループは、>値のある行ではなくファイルの終わりで終了する可能性があるため、このチェックはファイルの終わりでtrueの場合$limitでも行われます。$ingroup

最後に@longestgroup印刷された内容は\nトークン区切り文字として機能します。

答え3

awkを使用してください。

$ cat tst.awk
$2 >= 2 {
    max = getMax(cur,max)
    cur = ""
    next
}
{ cur = cur $2 ORS }
END {
    printf "%s", getMax(cur,max)
}
function getMax(a,b) {
    return ( gsub(ORS,"&",a) > gsub(ORS,"&",b) ? a : b )
}

$ awk -f tst.awk file
1.19819
1.1113829
1.0953443
1.9458343
1.345645
1.3847385794
1.3534344

答え4

<>読み込み入力およびトリガ演算子のための慣用的なソリューションです。

#!/usr/bin/env perl
use strict;
use warnings;
# https://unix.stackexchange.com/questions/766081/how-to-print-the-longest-sequence-of-lines-featuring-numbers-smaller-than-a-thre
my $threshold = 2.00;
my ($section, $maxsection, $len, $maxlen);
my $flipflop;
while (<>) {
    # Remove leading line number
    s/^(\d+)\s+//;
    # Flip flop operator
    # https://www.effectiveperlprogramming.com/2010/11/make-exclusive-flip-flop-operators/
    if ($flipflop = $_ <= $threshold .. $_ > $threshold) {
        if ($flipflop =~ /E0$/) {
            # End of section
            if (!defined($maxlen) || $len > $maxlen) {
                $maxsection = $section;
                $maxlen = $len;
            }
            $len = 0;
            $section = "";
        } else {
            $len++;
            $section .= $_;
        }
    }
}
# One last possible end of section
if ($flipflop && $len > $maxlen) {
    $maxsection = $section;
}
print $maxsection;

関連情報