Eliminar líneas específicas

Eliminar líneas específicas

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 es 1, 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 a F1;
  • $F0=@F[0]: asigna el valor del primer campo de la línea actual a F0;
% 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.pypor 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

información relacionada