
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 \t
a 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:
cut
selecciona sólo el primer fragmento (-f 1
) de una línea, dividiéndolo en cada espacio (-d ' '
);sort | uniq
ordenará 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
file
withgrep
; - 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.
- Extraiga todas las líneas relevantes de
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:
- Rendimiento: el tiempo de ejecución de este enfoque es significativamente mayor que el de las
awk
soluciones basadas (probéla respuesta de roaima). Al menos de un orden de magnitud. - Por otro lado, este enfoque funciona incluso si el archivo de entrada no está ordenado.
- 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?".