从数字列表中查找连续整数

从数字列表中查找连续整数

对于由换行符分隔的整数文件,我想搜索连续的整数,然后列出每个不间断序列的连续整数的数量,以及每个序列进入的方向(升序或降序)。

我的文件看起来像这样:

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

我想要的输出是:

4^
3^
3v

第一个字符指示连续数字的数量,第二个字符指示数字是升序还是降序。有没有办法在 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 的工作原理大致如下:它将逐行读取输入。对于每一行,它将执行条件为真的代码块。

代码块是花括号中的东西。条件是代码块之前的部分。

condition { code block }

BEGINEND是特殊条件,分别在第一行之前和最后一行之后为真。在这段代码中我们没有BEGIN.仅有的END

func不是一个条件。相反,它是一个稍后使用的函数声明。

第一个块的条件是NR == 1NR是记录数,实际上意味着行号。实际上,这意味着该块将在第一行执行,并且不再执行。在此块中,我们将变量初始化为正常值。

该块和大多数其他块都以该next语句结尾。next告诉 awk 放弃这个循环并加载下一行并开始下一个循环寻找要运行的块。通过next就位,我们有效地创建了一个大的 if else if 链。

下一个块的条件是$1 == prev+1 && dir == "v"。这测试当前数字是否比前一个数字大一以及运行方向当前是否向下。如果两者都为真,那么我们打印正在进行的向下运行并更新变量以开始新的向上运行。如果不是,则不会执行该块,awk 将查找下一个要执行的块。

以下条件和块与此类似。

倒数第二个块(该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 ▼

相关内容