¿Existe una solución perl o awk para este problema?

6

Tengo un archivo de entrada ( input.txt ) como a continuación.

id1      id2       name    weight 
53723848 12651711 timburnes 1.36667
53530214 12651711 timburnes 1.51191
53723848 53530214 timburnes 1.94
764157 52986038 ericcartman 0.861145
56797854 764157 ericcartman 1.35258
56797854 52986038 ericcartman 1.73781

Tenga en cuenta que la primera línea no es parte del archivo real, la he agregado aquí para mayor claridad .

Estoy tratando de extraer los valores de id1y id2para 2 archivos separados llamados unique.txt y duplicate.txt .

Si el weightvalor de mi columna es mayor que 1.5, significa que tengo identificadores duplicados . En este caso, moveré el id1valor al unique.txtarchivo y el id2valor al duplicate.txtarchivo.

Si mi columna de peso es menor a 1.5, significa que no tengo valores duplicados. Entonces, en este caso, moveré ambos id1y id2al archivo unique.txt .

Entonces, para la entrada anterior, espero la salida como,

Para el archivo unique.txt ,

53723848 timburnes
764157 ericcartman
56797854 ericcartman

Para el archivo duplicate.txt ,

12651711 timburnes
53530214 timburnes
52986038 ericcartman

Puedo encontrar los duplicados usando el siguiente código.

Para obtener los valores mayores que 1.5 basados ​​en la cuarta columna,

awk -F" " '$4 >= 1.5 { print $1" " $2" " $3" " $4}' file1.txt > Output.txt

Ahora, para valores superiores a 1.5, puedo usar el siguiente código para fusionar los identificadores duplicados en función de sus nombres.

  perl -ane 'foreach(@F[0..1]){$k{$F[2]}{$_}++}
           END{
                foreach $v (sort keys(%k)){
                    print "$_ " foreach(keys(%{$k{$v}})); 
                    print "$v\n"
                }; 
            } ' Output.txt

Sin embargo, no puedo obtener la salida de la manera que me gusta en el enfoque anterior.

EDITAR :

Estoy ejecutando el comando para mi entrada como se muestra a continuación.

awk '{
      if ($4 > 1.5) { 
          if (++dup[$2] == 1)  print $2, $3 > "duplicate.txt"
      } 
      else
          if (++uniq[$1] == 1) print $1, $3 > "unique.txt" 
}' << END
17412193 43979400 ericcartman 2.16667
21757330 54678379 andrewruss 0.55264
END 

Estoy obteniendo la salida como,

-bash-3.2$ cat unique.txt
21757330 a.andreev
-bash-3.2$ cat duplicate.txt
43979400 ericcartman

Sin embargo, el resultado que espero es,

cat unique.txt
17412193 ericcartman
21757330 andrewruss
54678379 andrewruss
cat duplicate.txt
43979400 ericcartman
Ramesh
fuente
¿Qué pasaría si $4menos que 1.5?
Cuonglm
@Gnouc, si $4es menor que 1.5, los agregaré al unique.txtarchivo. Además, antes de insertar algo que sea unique.txto duplicate.txtarchivo, voy a tener que comprobar si el valor ya está presente en el archivo. Si ya está presente, no necesito insertarlo nuevamente.
Ramesh
¿Qué significa "agregarlos"? ¿Qué sucede con $1y $2cuándo $4es inferior a 1,5?
Cuonglm
@Gnouc, agregarlos significa que estoy agregando los valores al unique.txtarchivo. Por lo tanto, supongo que si $4es inferior a 1,5, voy a añadir $1y $2a unique.txtpresentar.
Ramesh
"Tendré que verificar si el valor ya está presente", ¿qué valor? ¿Solo la ID o el par ID / nombre?
Glenn Jackman

Respuestas:

7

Aquí hay awksolución:

$ awk '
    $4 < 1.5 {
      uniq[$1] = $3;
      uniq[$2] = $3;
      next;
  }
  {
      uniq[$1] = $3;
      dup[$2] = $3;
      delete uniq[$2];
  }
  END {
    print "--unique.txt--";
    for(i in uniq) {
        print i,uniq[i]
    }
    print "";
    print "--duplicate.txt--";
    for(i in dup) {
        print i,dup[i]
    }
    }' file
--unique.txt--
764157 ericcartman
56797854 ericcartman
53723848 timburnes

--duplicate.txt--
53530214 timburnes
52986038 ericcartman
12651711 timburnes

Con tu segundo ejemplo:

$ awk '
    $4 < 1.5 {
      uniq[$1] = $3;
      uniq[$2] = $3;
      next;
  }
  {
      uniq[$1] = $3;
      dup[$2] = $3;
      delete uniq[$2];
  }
  END {
    print "--unique.txt--";
    for(i in uniq) {
        print i,uniq[i]
    }
    print "";
    print "--duplicate.txt--";
    for(i in dup) {
        print i,dup[i]
    }
    }' << END
> 17412193 43979400 ericcartman 2.16667
> 21757330 54678379 andrewruss 0.55264
END
--unique.txt--
21757330 andrewruss
54678379 andrewruss
17412193 ericcartman

--duplicate.txt--
43979400 ericcartman
Cuonglm
fuente
Muchas gracias. ¿Es posible para mí obtener los valores para archivar? Si lo uso ahora, obtengo el resultado impreso en la consola y no puedo verificarlo. :)
Ramesh
Reemplazar print i,uniq[i]por print i,uniq[i] >> "unique.txt". Haz lo mismo con dup. Una nota de que la salida no está ordenada.
Cuonglm
Lo intenté solo. Me sale un error de sintaxis.
Ramesh
¿Qué línea causa error de sintaxis?
Cuonglm
Lo siento, estaba usando comillas simples para el archivo. Creo que debería funcionar ahora con comillas dobles. Déjame comprobarlo :)
Ramesh
6
$ awk '{
      if ($4 > 1.5) { 
          if (++dup[$2] == 1)  print $2, $3 > "duplicate.txt"
      } 
      else
          if (++uniq[$1] == 1) print $1, $3 > "unique.txt" 
}' << END
53723848 12651711 timburnes 1.36667
53530214 12651711 timburnes 1.51191
53723848 53530214 timburnes 1.94
764157 52986038 ericcartman 0.861145
56797854 764157 ericcartman 1.35258
56797854 52986038 ericcartman 1.73781
END

$ cat unique.txt 
53723848 timburnes
764157 ericcartman
56797854 ericcartman

$ cat duplicate.txt 
12651711 timburnes
53530214 timburnes
52986038 ericcartman
Glenn Jackman
fuente
Por favor, vea la edición de mi pregunta. Ejecuté su comando y pegué el resultado que estoy obteniendo.
Ramesh
6

Aquí hay uno de Perl:

perl -lane '$F[3]>1.5 ? print STDERR "$F[1] $F[2]" : print STDOUT "$F[0] $F[2]"'\
 input.txt 2> duplicate.txt > unique.txt

No estoy buscando duplicados aquí, si entiendo su pregunta correctamente, ya lo ha hecho y si algo es un engaño o no depende del valor del último campo. Si no estoy entendiendo algo, hágamelo saber y lo actualizaré.

El código anterior produce

$ cat duplicate.txt 
12651711 timburnes
53530214 timburnes
52986038 ericcartman

$ cat unique.txt 
53723848 timburnes
764157 ericcartman
56797854 ericcartman
terdon
fuente
Su solución solo es adecuada para estas entradas, proporciona la salida deseada correcta pero con una lógica de OP incorrecta. El OP quiere 1) if $4 < 1.5, then write both entry ($1 $3) and ($2 $3) to unique.txt--- 2) if $4 >= 1.5, then write ($1 $3) to unique.txt and write ($2 $3) to duplicate.txt, if $2 was in unique.txt, remove its entry in unique.txt.
Cuonglm
@Gnouc, puede que tengas razón. Sinceramente, no tengo idea de lo que está pidiendo el OP en este momento. La pregunta es muy confusa y no veo relación entre la entrada y la (s) salida (s) deseada (s). Esperaré a que Ramesh lo aclare.
terdon
@terdon, lamento mucho la pregunta bastante confusa :) Intentaré actualizarla claramente en algún momento. Nuevamente, lamento no haber sido más claro :)
Ramesh
@Ramesh relájate! Como dije en mi comentario anterior, tengo gripe en este momento, por lo que es muy posible que solo esté siendo obtuso. No te preocupes por eso :)
terdon
@terdon, oh no. Espero que te mejores pronto :) ¿Es un MERSvirus?
Ramesh