Selecione apenas as primeiras linhas que contenham uma string repetida

0

Eu tenho um arquivo que se parece com isso:

2_00003 R034671 31.25   96  55  2   100 195 77  161 7e-07   47.8
2_00003 R034668 31.25   96  55  2   100 195 77  161 7e-07   47.8
2_00003 R034667 31.25   96  55  2   100 195 77  161 7e-07   47.8
2_00003 R034665 31.25   96  55  2   100 195 77  161 7e-07   47.8
2_00003 R034656 34.88   86  45  2   100 185 77  151 9e-07   47.4
2_00003 R034662 34.88   86  45  2   100 185 77  151 9e-07   47.4
2_00003 R034659 34.88   86  45  2   100 185 77  151 9e-07   47.4
2_00004 R014991 31.90   232 141 5   2   232 4   219 5e-28    111
2_00004 R009910 31.90   232 141 5   2   232 4   219 5e-28    111

Eu quero selecionar apenas as primeiras linhas dos grupos que começam com a mesma string na primeira coluna. Então, para o arquivo acima, quero selecionar:

2_00003 R034671 31.25   96  55  2   100 195 77  161 7e-07   47.8
2_00004 R014991 31.90   232 141 5   2   232 4   219 5e-28    111

Eu pensei em usar simplesmente

uniq -w 7 <file name>

Mas tenho dois problemas:

  1. Não tenho certeza se uniq informa sempre a primeira ocorrência (no meu caso, na primeira linha)
  2. às vezes no meu arquivo, a string na primeira coluna tem um número de caracteres maior que 7, então minha ideia não funcionará

Algum conselho?

    
por efrem 06.02.2015 / 18:47

4 respostas

3

Você poderia considerar o uso de sort -u como uma alternativa a uniq , especificando o primeiro campo separado por espaço em branco como chave:

$ sort -uk1,1 file
2_00003 R034671 31.25   96  55  2   100 195 77  161 7e-07   47.8
2_00004 R014991 31.90   232 141 5   2   232 4   219 5e-28    111

Como alternativa, você pode fazer algo assim em awk :

awk '$1!=last {last=$1; print}' file

que testa o primeiro campo de cada linha ( $1 ) em relação ao valor last e imprime a linha sempre que $1 é alterado, atualizando o valor last à medida que ocorre.

    
por steeldriver 06.02.2015 / 19:00
1

Outra abordagem em Python:

  • leia o arquivo
  • listar ocorrências exclusivas da primeira coluna
  • lista a primeira ocorrência na lista
#!/usr/bin/env python3
import sys
file = sys.argv[1]

with open(file) as src:
    lines = src.readlines()
for l in [[l for l in lines if l.startswith(f)][0] for f in set([l.split()[0] for l in lines])]:
    print(l, end = "")

Execute-o com o arquivo de texto como argumento:

python3 <script> <text_file>

Nota

Embora a opção acima seja rápida (testada em um arquivo > 1000000 linhas), ela pode ser drasticamente mais rápida (aprox. 15% nos testes que executei) se pudermos assumir a string no primeiro coluna não ocorre em outras posições nos registros (provavelmente uma suposição segura). Nesse caso, podemos ignorar a função startswith() :

#!/usr/bin/env python3
import sys
file = sys.argv[1]

with open(file) as src:
    lines = src.readlines()
for l in [[l for l in lines if f in l][0] for f in set([l.split()[0] for l in lines])]:
    print(l, end = "")
    
por Jacob Vlijm 07.02.2015 / 08:45
0

Você pode fazer isso em um script como este:

first_occurence.sh (configure para ser executável)

#!/bin/bash

# Set bash to separate words by newlines only, not spaces
IFS=$'\n'
# read input
input=("$(cat)")

# get a list of unique keys - split input by space with awk for any length
unique_values=($(printf "%s\n" "${input[*]}" | awk -F' ' '{ print $1 }' | uniq))

cur=0

# check each line of input for the key
for line in ${input[@]};
do  
    # wildcard matching
    if [[ "$line" == "${unique_values[$cur]}"* ]]
    then
        # print line if match, and move on to checking the next key
        printf "%s\n" "$line"
        cur=$((cur + 1))
    fi  
    # break the loop if we have used up all of our unique keys (only duplicates remain)
    if [ $cur -ge ${#unique_values[@]} ]
    then
        break
    fi  

done

Executar canalizando o arquivo em:

./first_occurence.sh < filename 
    
por Aaron D 06.02.2015 / 20:48
0

Eu acho que a solução da steeldriver usando sort é a melhor, mas se você quiser tentar outra coisa, verifique o seguinte script Python:

#!/usr/bin/python2
import re
def checking():
        if not check_list:
            result.append(list_of_lines[index - 1])
with open('/path/to/the/file') as f:
    list_of_lines = f.readlines()
    result = []
    for index in range(1, len(list_of_lines)):
        regex_current = re.search('^[0-9]_[0-9]+', list_of_lines[index])
        regex_previous = re.search('^[0-9]_[0-9]+', list_of_lines[index - 1])
        check_list = [x for x in result if x.split()[0] == regex_previous.group()]
        if regex_current == regex_previous:
            checking()
        else:
            checking()
print ''.join(result)
    
por heemayl 07.02.2015 / 05:54