숫자 목록에서 연속된 정수 찾기

숫자 목록에서 연속된 정수 찾기

줄 바꿈으로 구분된 정수 파일의 경우 연속된 정수를 검색한 다음 깨지지 않은 각 시퀀스의 연속된 정수 수와 각 시퀀스가 ​​진행되는 방향(오름차순 또는 내림차순)을 나열하고 싶습니다.

내 파일은 다음과 같습니다.

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.only 가 없습니다 END.

func조건이 아닙니다. 대신 나중에 사용되는 함수 선언입니다.

첫 번째 블록의 조건은 입니다 NR == 1. NR실제로 줄 번호를 의미하는 레코드 번호입니다. 사실상 이는 블록이 첫 번째 줄에서 실행되고 다시는 실행되지 않음을 의미합니다. 이 블록에서는 변수를 일반 값으로 초기화합니다.

이 블록과 대부분의 다른 블록은 next이 문으로 끝납니다. nextawk에게 이 루프를 포기하고 다음 줄을 로드하고 실행할 블록을 찾기 위해 다음 루프를 시작하도록 지시합니다. 그것을 제자리에 놓으면 next체인이 있다면 효과적으로 큰 효과를 얻을 수 있습니다.

다음 블록의 조건은 이다 $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 ▼

관련 정보