Imprime valores que são pelo menos 2 vezes maiores que os valores 3 passos acima e abaixo na mesma coluna

4

Eu tenho uma lista

2
2
2
3
2
2
2
4
2
2
2

Eu quero imprimir os valores que são pelo menos 2 vezes maiores que os valores 3 passos acima e abaixo na mesma coluna.

A saída deve ser

4

Como fazer isso? Eu tenho uma pergunta semelhante solicitada aqui , só para melhor ilustrar eu escrevo aqui, obrigado.

Atualização 20171006: Desculpe por simplificar o meu arquivo de entrada real, é realmente uma tabela em vez de uma lista que eu preciso selecionar em várias colunas (coluna 2, 3, 4 etc.) e imprimir a coluna 1. Como eu poderia incorporar as informações da coluna em tal roteiro?

A 2 2 2
B 2 2 2
C 2 2 2
D 3 3 3
E 2 2 2
F 2 2 2
G 2 2 2
H 4 4 4
I 2 2 2 
J 2 2 2 
K 2 2 2 

E para obter

H
    
por Johnny Tam 05.10.2017 / 08:10

5 respostas

5

Você pode fazer isso em awk . Você precisaria salvar as 6 linhas anteriores para comparar a terceira última linha com a 6ª última linha e a atual. Para isso, o truque comum é usar um buffer de anel, que é uma matriz indexada por NR%6 , em que 6 é o número de linhas que você deseja manter.

awk '
  NR > 6 {
    x = saved[NR%6]; y = saved[(NR - 3) % 6]; z = $0
    if (y >= 2*x && y >= 2*z) print y
  }
  {saved[NR % 6] = $0}'  < file

Para sua edição: salve a chave e o valor para comparar:

awk -v key=1 -v value=2 '
  NR > 6 {
    x = saved_value[NR%6]; y = saved_value[(NR - 3) % 6]; z = $value
    if (y >= 2*x && y >= 2*z) print saved_key[(NR - 3) % 6]
  }
  {saved_key[NR % 6] = $key; saved_value[NR % 6] = $value}'  < file

em que key é o índice da coluna que você deseja imprimir e value da coluna com os valores que você deseja comparar.

Ou com base na métrica que você deseja com base nas colunas 2, 3 e 4, como a média:

awk '
  {metric = ($2 + $3 + $4) / 3}
  NR > 6 {
    x = saved_metric[NR%6]; y = saved_metric[(NR - 3) % 6]; z = $metric
    if (y >= 2*x && y >= 2*z) print saved_key[(NR - 3) % 6]
  }
  {saved_key[NR % 6] = $key; saved_metric[NR % 6] = $metric}'  < file
    
por 05.10.2017 / 08:56
5

Sem ler o arquivo inteiro na memória:

paste <(tail -n+4 file.txt | head -n-3) <(head -n-6 file.txt) <(tail -n+7 file.txt) |
    awk '$1 >= 2*$2 && $1 >= 2*$3 {print $1}'

Isso precisa de um shell que possa lidar com <(...) de construções (f.i. AT & T ksh , bash ou zsh ) e uma implementação de head que ofereça suporte a compensações negativas.

Explicação: o comando paste acima coloca na mesma linha o valor atual, o valor 3 passos acima e o valor 3 passos abaixo; o comando awk verifica as condições 2 vezes maiores.

    
por 05.10.2017 / 08:34
2
Solução

Awk :

awk 'function mean(sum){ 
          m=sum/3; return (int(m) == m)? m: int(m)+1 
     }
     { a[NR]=$0 }
     END{ 
         for(i=4;i<=NR-3;i++) 
             if (a[i]>=mean(a[i-3]+a[i-2]+a[i-1])*2 &&
                a[i]>=mean(a[i+3]+a[i+2]+a[i+1])*2) 
             print a[i] 
     }' file
  • a[NR]=$0 - coletando todos os valores na matriz a indexado com números de registro NR

A saída:

4
    
por 05.10.2017 / 08:32
2

Se você só precisa comparar com 3 rd valor acima / abaixo apenas , então é mais fácil com o comando abaixo awk .

awk -vRS='' '{for (i=4;i<=NF;i++) if ($i>=$(i-3)*2 && $i>=$(i+3)*2 ) print $i}' infile

Ou resumindo.

awk -vRS='' '{for (i=4;i<=NF;i++) if ($i>=$(i%3)*2) print $i}' infile
    
por 05.10.2017 / 09:09
1

Então você teria que manter uma janela deslizante de 3 + 1 + 3 linhas de entrada para poder fazer isso.

awk -vn=3 -va=2 'BEGIN { N=2*n+1 } { t=(NR-n)%N; m=NR%N; b=(NR+n)%N; w[b]=$0 } NR >= N && w[m] >= a*w[t] && w[m] >= a*w[b] { print w[m] }' file

Isso imprimiria todos os valores preenchendo os critérios, com a vantagem adicional de poder modificar facilmente a distância ajustando a variável n na linha de comando (alterar -vn=3 ) e o peso alterando a (alterar -va=2 ).

O código armazena os últimos N valores onde N é 2 * n + 1 em um buffer cíclico w . Se o valor do meio, w[m] , for maior que a vezes o primeiro valor no buffer, w[t] ( t para "top") e a vezes maior que o último valor no buffer, w[b] ( b para "bottom"), então é impresso.

O script awk foi desvendado:

BEGIN   { N = 2*n + 1 }

        {
            t = (NR - n)%N
            m = NR%N
            b = (NR + n)%N
            w[b] = $0
        }

NR >= N && w[m] >= a*w[t] && w[m] >= a*w[b] { print w[m] }
    
por 05.10.2017 / 09:02

Tags