数値リストで連続した整数を見つける

数値リストで連続した整数を見つける

改行で区切られた整数ファイルの場合は、連続した整数を検索してから、壊れていない各シーケンスの連続した整数の数と、各シーケンスが進む方向(昇順または降順)をリストしたいと思います。

私のファイルは次のとおりです。

2
3
4
5
1
7
4
5
6
3
2
1

私が望む出力は次のとおりです。

4^
3^
3v

最初の文字は連続した数字を表し、2番目の文字は数字が昇順か降順かを示します。 Bashでこれを行う方法はありますか?

答え1

Bashではなくawkで。ほとんどの人はbash / shellスクリプトの公正なゲームを検討しています。多くの人。少なくともそれが私にとってうまくいく方法です。

func printrun() {
  if(run > 1) {
    print run""dir
  }
}
NR == 1 {
  #print $1" first"
  prev = $1
  dir = "-"
  run = 1
  next
}
$1 == prev+1 && dir == "v" {
  #print $1" up from down"
  printrun()
  prev = $1
  dir = "^"
  run = 2
  next
}
$1 == prev+1 {
  #print $1" up"
  prev = $1
  dir = "^"
  run++
  next
}
$1 == prev-1 && dir == "^"  {
  #print $1" down from up"
  printrun()
  prev = $1
  dir = "v"
  run = 2
  next
}
$1 == prev-1 {
  #print $1" down"
  prev = $1
  dir = "v"
  run++
  next
}
{
  #print $1" else"
  printrun()
  prev = $1
  dir = "-"
  run = 1
}
END {
  #print "end"
  printrun()
}

私はコードを圧縮するためにifとelse ifチェーンのバリエーションを試しましたが、このバリエーションが最も明確で読みやすいことがわかりました。

別名で保存run.awk

こうして走る

$ awk -f run.awk inputfile

またはパイプ入力

$ commandproducinginput | awk -f run.awk

説明する:

awkはおおよそ次のように動作します。入力を1行ずつ読みます。各行に対して条件が真のコードブロックを実行します。

コードブロックは中かっこ内にあります。条件はコードブロックの前半です。

condition { code block }

BEGINそして、END最初の行の前と最後の行の後にそれぞれ真の特殊条件です。このコードにはBEGIN.onlyはありませんEND

func条件ではありません。代わりに、後で使用される関数宣言です。

最初のブロックの条件はですNR == 1NR実際に行番号を意味するレコード番号です。実際、これはブロックが最初の行で実行され、再び実行されないことを意味します。このブロックでは、変数を標準値に初期化します。

このブロックと他のほとんどのブロックはnextこのステートメントで終わります。nextawkにこのループを放棄し、次の行をロードして実行するブロックを見つけるために次のループを開始するように指示します。それを所定の位置に置くと、nextチェーンがあれば効果的に大きな効果を得ることができます。

次のブロックの条件はです$1 == prev+1 && dir == "v"。これは、現在の数字が前の数字よりも大きいかどうか、移動方向が現在下向きであるかどうかをテストします。両方が真の場合は、進行中のダウンストリーム実行を印刷し、変数を更新して新しいアップリンク実行を開始します。そうでない場合、ブロックは実行されず、awk は実行する次のブロックを探します。

以下の条件とブロックは同様です。

2番目のブロック(ENDこのブロックの前のブロック)は無条件ブロックです。これは、各行に対して実行されることを意味します。前のブロックのステートメントのために前のブロックがnext実行されなかった場合にのみ、ブロックが実行されます。実際、このブロックはif else ifチェーンの「else」です。

数値が連続した上または下ではない場合、このブロックに到達します。したがって、このブロックのコードは実行終了に対応する変数を設定します。

擬似コードでは、コードは次のようになります。

if first line:
  init vars and set run to none
else if now going up but was going down:
  print ongoing run down and start a run up
else if now going up:
  start or continue run up
else if now going down but was going up:
  print ongoing run up and start a run down
else if now going down:
  start or continue run down
else:
  print ongoing run and set run to none
if end of input:
  print ongoing run

答え2

awk 'function prnt(Xdir){ if (c)print c+1, Xdir; c=0 } 
(pre+1==$0){ prev_dir=dir; dir="▲"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=$0; next }
(pre==$0+1){ prev_dir=dir; dir="▼"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=$0; next }
 c{ prnt(dir) } 
{ pre= $0}
END{ prnt(dir) }' infile

4 ▲
3 ▲
3 ▼

関連情報