Cómo eliminar nombres duplicados e imprimir una matriz después de nombres únicos

Cómo eliminar nombres duplicados e imprimir una matriz después de nombres únicos

Cómo contraer categorías KO con el mismo nombre e imprimir los nombres de genes que se asignaron a cada categoría en una matriz, como en el ejemplo siguiente.

Tengo esto:

K00002  gene_65472
K00002  gene_212051
K00002  gene_403626
K00003  gene_666
K00003  gene_5168
K00003  gene_7635
K00003  gene_12687
K00003  gene_175295
K00003  gene_647659
K00003  gene_663019
K00004  gene_88381
K00005  gene_30485
K00005  gene_193699
K00005  gene_256294
K00005  gene_307497

Y quiero esto:

K00002  gene_65472  gene_212051 gene_403626             
K00003  gene_666    gene_5168   gene_7635   gene_12687  gene_175295 gene_647659 gene_663019
K00004  gene_88381                      
K00005  gene_30485  gene_193699 gene_256294 gene_307497 

El siguiente comando funcionó (tomado dela respuesta de roaima):

tr -d '\r' < file| awk '$1 != p { if (p>"") {printf "\n"} printf "%s",$1; p=$1 } { printf "\t%s",$2 } END { if(p>"") {printf "\n"} }' > output

Respuesta1

Mas de lo mismo

awk '$1 != p { if (p>"") {printf "\n"} printf "%s",$1; p=$1 } { printf "\t%s",$2 } END { if(p>"") {printf "\n"} }' datafile

K00002  gene_65472      gene_212051     gene_403626
K00003  gene_666        gene_5168       gene_7635       gene_12687      gene_175295     gene_647659     gene_663019
K00004  gene_88381
K00005  gene_30485      gene_193699     gene_256294     gene_307497

Si no quieres la separación porpestañaluego cambie el \ta un espacio.

Así es como funciona:

# Each line is processed in turn. "p" is the previous line's key field value

# Key field isn't the same as before
$1 != p {
    # Flush this line if we have printed something already
    if (p > "") { printf "\n" }

    # Print the key field name and set it as the current key field
    printf "%s", $1; p = $1
}

# Every line, print the second value on the line
{ printf "\t%s", $2 }

# No more input. Flush the line if we have already printed something
END {
    if (p > "") { printf "\n" }
}

Desde elimpreciso comentariosestáshaciendoEn contra de las respuestas de todos, parece que el problema subyacente es que está utilizando un archivo de datos generado en un sistema Windows y espera que funcione en una plataforma UNIX/Linux. No hagas eso. O si es necesario, primero convierta el archivo al formato correcto.

dos2unix < datafile | awk '...'       # As above

tr -d '\r' < data file | awk '...'    # Also as above

Respuesta2

archivo:

K00002  gene_65472
K00002  gene_212051
K00002  gene_403626
K00003  gene_666
K00003  gene_5168
K00003  gene_7635
K00003  gene_12687
K00003  gene_654221
K00003  gene_663019
K00004  gene_88381
K00005  gene_30485
K00005  gene_193699
K00005  gene_256294

Usando awk:

awk '1 {if (a[$1]) {a[$1] = a[$1]" "$2} else {a[$1] = $2}} END {for (i in a) { print i,a[i]}}' file

producción:

K00002 gene_65472 gene_212051 gene_403626
K00003 gene_666 gene_5168 gene_7635 gene_12687 gene_654221 gene_663019
K00004 gene_88381
K00005 gene_30485 gene_193699 gene_256294

yo tome estocorreocomo referencia.

Respuesta3

usando molinerohttp://johnkerl.org/miller/doc
con

mlr --csv --implicit-csv-header --headerless-csv-output cat -n -g 1 then label a,b,c then reshape -s a,c then unsparsify --fill-with "" input.csv

y este ejemplo de entrada csv

A,234
A,4945
B,8798
B,8798
B,790

Usted tendrá

A,234,4945,
B,8798,8798,790

Respuesta4

Suponiendo que sus valores no contienen espacios y están separados por espacios; asumiendo también que sus datos están en un archivo llamado file(consulte a continuación una versión separada por tabulaciones):

for x in $(<file cut -d ' ' -f 1 | sort | uniq); do
    printf '%s %s\n' "$x" "$(grep "$x" file | cut -d ' ' -f 2- | tr '\n' ' ' | sed 's/.$//')"
done

Esta voluntad:

  • Extraiga los distintos valores del primer campo:
    • cutselecciona sólo el primer fragmento ( -f 1) de una línea, dividiéndolo en cada espacio ( -d ' ');
    • sort | uniqordenará los valores del primer campo y generará cada uno de ellos una sola vez (alternativamente,más corto y más eficiente: sort -u);
  • Para cada:
    • Extraiga todas las líneas relevantes de filewith grep;
    • Quíteles el primer campo con cut( -f 2-significa "tomar el segundo campo y los siguientes");
    • Traducir el resto a una lista de valores separados por espacios ( tr);
    • Deshágase del último carácter, un espacio innecesario, usando sed(sí, esto es realmente poco elegante);
    • Concatene el resultado con el valor del primer campo e imprima en la salida estándar.

Si su entrada está separada por tabulaciones y desea una salida separada por tabulaciones, el código anterior se convierte en:

for x in $(<file cut -f 1 | sort | uniq); do
    printf '%s\t%s\n' "$x" "$(grep "$x" file | cut -f 2- | tr '\n' '\t' | sed 's/.$//')"
done

Notas:

  1. Rendimiento: el tiempo de ejecución de este enfoque es significativamente mayor que el de las awksoluciones basadas (probéla respuesta de roaima). Al menos de un orden de magnitud.
  2. Por otro lado, este enfoque funciona incluso si el archivo de entrada no está ordenado.
  3. A pesar de que este tipo de solución es una forma rápida (¿y sucia?) de hacer el trabajo de manera efectiva, generalmente no es aconsejable procesar texto con bucles de shell; ver como referencia "¿Por qué se considera una mala práctica utilizar un bucle de shell para procesar texto?".

información relacionada