Eliminación de entradas superpuestas basadas en valores de inicio/fin en bash

Resuelto Dody asked hace 10 meses • 0 respuestas

Tengo un archivo de entradas delimitadas por tabulaciones que tienen una posición inicial y final

# Name \t Start \t End
Name1 \t 1 \t 3
Name2 \t 7 \t 9
Name3 \t 5 \t 8
Name4 \t 5 \t 6

Quiero eliminar líneas que se superponen con líneas anteriores. En este ejemplo, el resultado deseado sería

Name1 \t 1 \t 3
Name2 \t 7 \t 9
Name4 \t 5 \t 6

Lo que tengo hasta ahora:

#!/bin/bash
while IFS=$'\n' read line; do
     # Assign variable names
     name=$(echo $line | cut -f 1)
     start=$(echo $line | cut -f 2)
     end=$(echo $line | cut -f 3)
     # I envision an if statement structured so that:
     # if [ $end < $PreviousStart ] || [ $start > $PreviousEnd ] ; then echo $line >> output.txt
done < file.txt

Aquí es donde me quedo atascado porque necesitaría verificar cada línea de salida.txt (todas las líneas anteriores de mi archivo original) y solo imprimir $line si la declaración if se cumple para todas las líneas actuales de salida.txt. Estaba pensando que awk podría tener una solución para esto que sea menos tortuosa...

Cualquier ayuda es muy apreciada

Dody avatar Feb 16 '24 07:02 Dody
Aceptado

Puede mantener las posiciones iniciales y finales anteriores que no se superponen como índices y valores en una matriz en awk para poder iterar fácilmente a través de ellas en cada registro para probar si las posiciones iniciales y finales actuales se superponen con cualquiera de ellas y omitir el registro actual. si lo hacen:

awk '-F\t' '{for(s in a)if($2<=a[s]&&s<=$3)next;a[$2]=$3}1' file.txt

Demostración: https://awk.js.org/?snippet=REkxdr

blhsing avatar Feb 16 '2024 01:02 blhsing

Supuestos:

  • A medida que leemos una nueva línea, debemos comprobar si hay superposiciones con todas las líneas anteriores que no se superponen.
  • si una nueva línea no se superpone con ninguna de las líneas anteriores que no se superponen, entonces...
  • a) guardamos la nueva línea como un nuevo miembro del grupo de líneas que no se superponen y
  • b) imprimir la nueva línea en stdout

Una awkidea:

awk '
BEGIN { FS=OFS="\t" }
      { for (i=1; i<=cnt; i++)                            # loop through array of previous lines
            if ( ( $2 >= start[i] && $2 <= end[i] ) ||    # does current "start" overlap with a previous line?
                 ( $3 >= start[i] && $3 <= end[i] )    )  # does current "end" overlap with a previous line?
                 next                                     # if there is an overlap then skip this line and process the next line of input 

        start[++cnt] = $2                                 # we have a new non-overlapping line so save the start and end points
        end[cnt] = $3
        print                                             # print current line to stdout
      }
' file.txt

Esto genera:

Name1   1       3
Name2   7       9
Name4   5       6
markp-fuso avatar Feb 16 '2024 01:02 markp-fuso
#!/usr/bin/bash
declare name
declare -a startArr endArr
declare -i start end overlapping

while IFS=$'\t' read -r name start end; do
   if ((${#name}==0)); then continue; fi
   overlapping=0
   for ((i=0; i<${#startArr[*]}; i++))
      {
      if (( start >= ${startArr[i]} && start <= ${endArr[i]} || end >= ${startArr[i]} && end <= ${endArr[i]} || start < ${startArr[i]} && end > ${endArr[i]} )); then 
         overlapping=1;
         break;
      fi
      }
   if ((overlapping)); then continue; fi
   echo "$name"$'\t'"$start"$'\t'"$end"
   startArr+=($start); endArr+=($end)
 done < file1

archivo1:

Name1   1   3
Name2   7   9
Name3   5   8
Name4   5   6
Name5   4   10   # edited this line , other case of overlapping
Schmaehgrunza avatar Feb 16 '2024 21:02 Schmaehgrunza