
Me gustaría eliminar algunas líneas de un archivo csv.
Las reglas son bastante simples (mantenga la línea si):
- Es la primera línea del archivo.
- El primer valor es diferente del primer valor de la fila anterior.
- El segundo valor ha aumentado al menos 10 con respecto a la línea mantenida anterior.
Fuente
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
Estaba pensando en hacer esto con awk y algunas declaraciones if, pero no estoy seguro de poder crear una variable que se transfiera entre el procesamiento de registros.
EDITAR: esto estaba oculto en la sección de comentarios (de mi parte):
Acabo de descubrir que las variables se pueden utilizar entre registros. Algo que no funciona como C. Eliminaré esta pregunta a menos que alguien dé una respuesta que considere útil para otros o alguien me pida que proporcione la respuesta.
Respuesta1
Ya que está etiquetado con 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
Respuesta2
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]}
: si el número de la línea actual es1
, el primer campo de la línea actual es igual al primer campo de la línea anterior o el segundo campo de la línea actual es mayor o igual al segundo campo de la línea anterior, imprime la línea actual y asigna el valor de la línea actual segundo campo aF1
;$F0=@F[0]
: asigna el valor del primer campo de la línea actual 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
Respuesta3
Usando una secuencia de comandos de 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 el script anterior y péguelo en un archivo llamado, csvfilter.py
por ejemplo.
Hazlo ejecutable usando chmod +x csvfilter.py
.
Luego puedes ejecutarlo desde la línea de comandos con el archivo csv para procesar (guardé tu ejemplo de la pregunta 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
El script no modificará el archivo original, solo imprimirá la nueva versión en la salida estándar. Además, se descartará cualquier formato previo que utilice espacios.
Para reemplazar el archivo original con la versión modificada, redirija la salida al archivo original:
$ ./csvfilter.py source.csv > source.csv
También puedes guardar la versión modificada como un archivo:
$ ./csvfilter.py source.csv > modified.csv