Remove linha inteira em um arquivo se a primeira coluna for repetida

6

Eu tenho um arquivo contendo duas colunas e 10 milhões de linhas. A primeira coluna contém muitos valores repetidos, mas há um valor distinto na coluna 2. Desejo remover as linhas repetidas e quero manter apenas uma usando awk . Nota: o arquivo é classificado com valores na coluna 1. Por exemplo:

1.123 -4.0
2.234 -3.5
2.234 -3.1
2.234 -2.0
4.432 0.0
5.123 +0.2
8.654 +0.5
8.654 +0.8
8.654 +0.9
.
.
.
.

Saída esperada

1.123 -4.0
2.234 -3.5
4.432 0.0
5.123 +0.2
8.654 +0.5
.
.
.
.
    
por Nilesh 08.10.2014 / 12:38

2 respostas

13

Algumas maneiras:

  1. awk

     
    awk '!a[$1]++' file
    

    Esta é uma maneira muito condensada de escrever isso:

    awk '{if(! a[$1]){print; a[$1]++}}' file
    

    Portanto, se o primeiro campo atual ( $1 ) não estiver na matriz a , imprima a linha e adicione o primeiro campo a a . Da próxima vez que virmos esse campo, ele estará na matriz e, portanto, não será impresso.

  2. Perl

    perl -ane '$k{$F[0]}++ or print' file
    

    ou

    perl -ane 'print if !$k{$F[0]}++' file
    

    Isso é basicamente o mesmo que o awk one. O -n faz com que o perl leia o arquivo de entrada linha por linha e aplique o script fornecido por -e a cada linha. O -a dividirá automaticamente cada linha no espaço em branco e salvará os campos resultantes no array @F . Finalmente, o primeiro campo é adicionado ao hash %k e, se ainda não estiver lá, a linha é impressa. A mesma coisa poderia ser escrita como

    perl -e 'while(<>){
                @F=split(/\s+/); 
                print unless defined($k{$F[0]}); 
                $k{$F[0]}++;
             }' file
    
  3. Coreutils

    rev file | uniq -f 1 | rev
    

    Este método funciona primeiro invertendo as linhas em file , de modo que, se uma linha for 12 345, agora será 543 21. Em seguida, usamos uniq -f 1 para ignorar o primeiro campo, ou seja, a coluna em que 543 está. Há campos dentro de file . Usar uniq aqui tem o efeito de filtrar todas as linhas duplicadas, mantendo apenas 1 de cada. Por fim, colocamos as linhas de volta na ordem original com outro reverso.

  4. Classificação do GNU (como sugerido por @ StéphaneChazelas)

    sort -buk1,1
    

    O sinal -b ignora os espaços em branco iniciais e o -u significa imprimir apenas campos exclusivos. O bit inteligente é o -k1,1 . O -k flag define o campo para classificar. Ele pega o formato geral de -k POS1[,POS2] , o que significa apenas olhar para os campos POS1 através de POS2 ao ordenar. Então, -k1,1 significa apenas olhar para o 1º campo. Dependendo dos seus dados, talvez você queira adicionar também uma destas opções:

     -g, --general-numeric-sort
          compare according to general numerical value
     -n, --numeric-sort
          compare according to string numerical value
    
por 08.10.2014 / 12:59
4

Se a primeira coluna tiver sempre 5 caracteres, você pode simplesmente usar uniq :

uniq -w 5 file

Se não, use awk :

awk '$1!=a{print $0; a=$1}' file

O primeiro seria definitivamente mais rápido com um arquivo enorme.

    
por 08.10.2014 / 12:54

Tags