Conte o maior número de padrões consecutivos

4

Eu tenho um arquivo de sequência:

$ cat file
CACCGTTGCCAAACAATG
TTAGAAGCCTGTCAGCCT
CATTGCTCTCAGACCCAC
GATGTACGTCACATTAGA
ACACGGAATCTGCTTTTT
CAGAATTCCCAAAGATGG

Eu quero calcular o trecho mais longo de C + T. Eu só poderia contar o C + T total, mas quero o trecho mais longo.

$ cat file | awk '{ print $0, gsub(/[cCtT]/,"",$1)}'
CACCGTTGCCAAACAATG 9
TTAGAAGCCTGTCAGCCT 10
CATTGCTCTCAGACCCAC 12
GATGTACGTCACATTAGA 8
ACACGGAATCTGCTTTTT 11
CAGAATTCCCAAAGATGG 7

O Resultado esperado seria mostrar o trecho C + T mais longo.

CACCGTTGCCAAACAATG 9 2
TTAGAAGCCTGTCAGCCT 10 3
CATTGCTCTCAGACCCAC 12 5
GATGTACGTCACATTAGA 8 2
ACACGGAATCTGCTTTTT 11 6
CAGAATTCCCAAAGATGG 7 5
    
por CN_229133 29.06.2018 / 11:32

5 respostas

5

FWIW aqui está uma maneira de fazer isso em perl, usando max de List::Util

$ perl -MList::Util=max -lpe '$_ .= " " . max 0, map length, /[CT]+/gi' file
CACCGTTGCCAAACAATG 2
TTAGAAGCCTGTCAGCCT 3
CATTGCTCTCAGACCCAC 5
GATGTACGTCACATTAGA 2
ACACGGAATCTGCTTTTT 6
CAGAATTCCCAAAGATGG 5
    
por 29.06.2018 / 12:33
4
$ awk '{ split($0, a, "[^CTct]+"); m=0
         for (i in a) {
             len=length(a[i])
             if (len > m) m=len
         }
         print $0, m  }' file
CACCGTTGCCAAACAATG 2
TTAGAAGCCTGTCAGCCT 3
CATTGCTCTCAGACCCAC 5
GATGTACGTCACATTAGA 2
ACACGGAATCTGCTTTTT 6
CAGAATTCCCAAAGATGG 5

Este programa awk divide cada linha em execuções de qualquer coisa que não seja maiúscula ou minúscula C ou T . Em seguida, ele faz um loop nos bits que resultam na divisão, encontrando o mais longo. Em seguida, imprime a linha original junto com o comprimento máximo encontrado.

Desde que a Roman analisou os horários de várias soluções, veja uma solução mais rápida:

awk -F "[^CTct]+" '
    m = 0
    for (i = 1; i <= NF; ++i) {
        len = length($i)
        if (len > m) m = len
    }
    print m' file | paste file -

É mais rápido, pois só divide as linhas uma vez. O primeiro código também tenta dividir as linhas de entrada nos espaços em branco.

O sincronismo usando mawk mostra 0.79s em 500.000 linhas. A primeira solução usa 1.69s nos mesmos dados, mostrando que é provavelmente a operação dividida que leva mais tempo.

    
por 29.06.2018 / 11:48
3

Com sed (assumindo não mais do que 19 caracteres por linha), apenas por diversão e usando as propriedades gananciosas do RE correspondente:

sed '
  h;y/cCtT/xxxx/;x;H;s/./x/g;G
  s/^\(x*\).*\n.*.*\n/ /
  s/^x\{10\}/1/;s/$/:9876543210xxxxxxxxx/
  s/^\(1*\)\(x*\) \(.*\):.*\(.\).\{9\}$/ /'

Uma variação na solução de @ Kusalananda:

awk -F '[^cCtT]+' '
  {
    max = 0
    for (i = 1; i <= NF; i++)
      if ((l = length($i)) > max)
        max = l
    print $0, max
  }'
    
por 29.06.2018 / 14:53
3

Solução mais rápida do GNU awk :

awk -v FPAT='[ctCT]+' \
'{ 
     max_l = t_len = 0;
     for (i=1; i <= NF; i++) {
         len = length($i);
         if (len > max_l) max_l = len;
         t_len += len
     }
     print $0, t_len, max_l
 }' inputfile

A saída:

CACCGTTGCCAAACAATG 9 2
TTAGAAGCCTGTCAGCCT 10 3
CATTGCTCTCAGACCCAC 12 5
GATGTACGTCACATTAGA 8 2
ACACGGAATCTGCTTTTT 11 6
CAGAATTCCCAAAGATGG 7 5

Comparação de desempenho de tempo (teste inputfile tem cerca de 120000 linhas):

$ time awk -v FPAT='[ctCT]+' '{ max_l = t_len = 0; for (i=1; i <= NF; i++) { len = length($i); if (len > max_l) max_l = len; t_len += len } print $0, t_len, max_l }' inputfile > /dev/null

real    0m1.018s
user    0m0.948s
sys 0m0.012s

$ time awk '{ split($0, a, "[^CTct]+"); m=0; for (i in a) { len=length(a[i]); if (len > m) m=len } print $0, m }' inputfile > /dev/null

real    0m1.802s
user    0m1.688s
sys 0m0.028s

$ time perl -MList::Util=max -lpe '$_ = "$_ " . max map { length $_ } /[CT]*/gi' inputfile > /dev/null

real    0m1.216s
user    0m1.160s
sys 0m0.016s

$ time sed 'h;y/cCtT/xxxx/;x;H;s/./x/g;G; s/^\(x*\).*\n.*.*\n/ /; s/^x\{10\}/1/;s/$/:9876543210xxxxxxxxx/; s/^\(1*\)\(x*\) \(.*\):.*\(.\).\{9\}$/ /' inputfile > /dev/null

real    1m4.165s
user    1m2.784s
sys 0m0.352s
    
por 29.06.2018 / 13:50
0

Tente também

awk '
        {T0 = $0
         while (match (T0, /[CTct]+/))  {if (RLENGTH > MX) MX = RLENGTH
                                         T0 = substr (T0, RSTART+RLENGTH)
                                        }
         print $0, MX
        }
' file

o tempo é um pouco mais rápido do que as outras propostas awk .

    
por 15.10.2018 / 18:26