
Gostaria de remover algumas linhas de um arquivo csv.
As regras são bastante simples (mantenha a linha se):
- É a primeira linha do arquivo.
- O primeiro valor é diferente do primeiro valor da linha anterior.
- O segundo valor aumentou em pelo menos 10 em relação à linha mantida anterior.
Fonte
Test1, 0.0, 1
Test1, 0.2, 1
Test1, 10.0, 3
Test2, 0.1, 1
Test2, 0.3, 3
Test2, 1.0, 5
Test2, 11.0, 7
Resultado
Test1, 0.0, 1
Test1, 10.0, 3
Test2, 0.1, 1
Test2, 11.0, 7
Eu estava pensando em fazer isso com o awk e algumas instruções if, mas não tenho certeza se posso fazer uma variável que seja transferida entre o processamento de registros.
EDIT: isso estava escondido na seção de comentários (de mim):
Acabei de descobrir que as variáveis podem ser utilizadas entre registros. Algo que não funciona como C. Retirarei esta pergunta, a menos que alguém dê uma resposta que considero útil para outras pessoas ou alguém me peça para fornecer a resposta.
Responder1
Já que está marcado com awk
awk -F", *" 'x!=$1||$2>=y+10{y=$2;print}{x=$1}' file
Test1, 0.0, 1
Test1, 10.0, 3
Test2, 0.1, 1
Test2, 11.0, 7
Responder2
Usando Perl:
perl -lane 'if($.==1||"$F[0]"ne"$F0"||$F[1]>=$F1+10){print;$F1=@F[1]}$F0=@F[0]' file
Expandido:
if($. == 1 || "$F[0]" ne "$F0" || $F[1] >= $F1 + 10){
print;
$F1 = @F[1]
}
$F0 = @F[0]
if($.==1||"$F[0]"ne"$F0"||$F[1]>=$F1+10){print;$F1=@F[1]}
: se o número da linha atual for1
, o primeiro campo da linha atual é igual ao primeiro campo da linha anterior ou o segundo campo da linha atual é maior ou igual ao segundo campo da linha anterior, imprime a linha atual e atribui o valor da linha atual segundo campo paraF1
;$F0=@F[0]
: atribui o valor do primeiro campo da linha atual aF0
;
% cat file
Test1, 0.0, 1
Test1, 0.2, 1
Test1, 10.0, 3
Test2, 0.1, 1
Test2, 0.3, 3
Test2, 1.0, 5
Test2, 11.0, 7
% perl -lane 'if($.==1||"$F[0]"ne"$F0"||$F[1]>=$F1+10){print;$F1=@F[1]}$F0=@F[0]' file
Test1, 0.0, 1
Test1, 10.0, 3
Test2, 0.1, 1
Test2, 11.0, 7
Responder3
Usando um script Python:
#! /usr/bin/env python3
import sys
with open (sys.argv[1]) as f:
rows=[list(map(str.strip, line.split(','))) for line in f.readlines()]
result=rows[0:1]
for r in rows:
if r[0] != result[-1][0] or float(r[1]) >= float(result[-1][1])+10:
result.append(r)
print("\n".join([",".join(res) for res in result]))
Copie o script acima e cole-o em um arquivo chamado, csvfilter.py
por exemplo.
Torne-o executável usando chmod +x csvfilter.py
.
Então você pode executá-lo a partir da linha de comando com o arquivo csv para processar (salvei seu exemplo da pergunta como source.csv
) como argumento:
$ ./csvfilter.py source.csv
Test1,0.0,1
Test1,10.0,3
Test2,0.1,1
Test2,11.0,7
O script não modificará o arquivo original, apenas imprimirá a nova versão na saída padrão. Além disso, qualquer formatação anterior com espaços será descartada.
Para substituir o arquivo original pela versão modificada, redirecione a saída de volta para o arquivo original:
$ ./csvfilter.py source.csv > source.csv
Você também pode salvar a versão modificada como um arquivo:
$ ./csvfilter.py source.csv > modified.csv