
So reduzieren Sie KO-Kategorien mit demselben Namen und drucken Gennamen, die den einzelnen Kategorien im Array zugewiesen wurden, wie im folgenden Beispiel.
Ich habe das:
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
Und will dies:
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
Der folgende Befehl funktionierte (entnommen ausroaimas Antwort):
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
Antwort1
Mehr vom Gleichen
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
Wenn Sie keine Trennung wünschen durchTabdann ändern Sie es \t
in ein Leerzeichen.
So funktioniert das:
# 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" }
}
Von demvage Kommentaredu bistHerstellungEntgegen den Antworten aller scheint das zugrunde liegende Problem darin zu liegen, dass Sie eine auf einem Windows-System generierte Datendatei verwenden und erwarten, dass sie auf einer UNIX/Linux-Plattform funktioniert. Tun Sie das nicht. Oder wenn es unbedingt sein muss, konvertieren Sie die Datei zuerst in das richtige Format.
dos2unix < datafile | awk '...' # As above
tr -d '\r' < data file | awk '...' # Also as above
Antwort2
Datei:
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
Mit 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
Ausgabe:
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
Ich habe das genommenPostals Referenz.
Antwort3
mit Millerhttp://johnkerl.org/miller/doc
mit
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
und dieses Beispiel einer CSV-Eingabe
A,234
A,4945
B,8798
B,8798
B,790
Du wirst haben
A,234,4945,
B,8798,8798,790
Antwort4
Vorausgesetzt, Ihre Werte enthalten keine Leerzeichen und sind durch Leerzeichen getrennt; vorausgesetzt außerdem, dass sich Ihre Daten in einer Datei mit dem Namen befinden file
(eine durch Tabulatoren getrennte Version finden Sie weiter unten):
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
Dieser Wille:
- Extrahieren Sie die unterschiedlichen Werte des ersten Felds:
cut
wählt nur den ersten Abschnitt (-f 1
) einer Zeile aus und unterbricht ihn an jedem Leerzeichen (-d ' '
);sort | uniq
sortiert die Werte des ersten Feldes und gibt jeden Wert nur einmal aus (alternativkürzer und effizienter:sort -u
);
- Für jede:
- Extrahieren Sie alle relevanten Zeilen
file
mitgrep
; - Entfernen Sie das erste Feld von ihnen mit
cut
(-f 2-
bedeutet „nehmen Sie das zweite und die folgenden Felder“); - Übersetzen Sie den Rest in eine Liste durch Leerzeichen getrennter Werte (
tr
); - Entfernen Sie das letzte Zeichen – ein nicht benötigtes Leerzeichen – mit
sed
(ja, das ist wirklich unelegant); - Verketten Sie das Ergebnis mit dem Wert des ersten Felds und drucken Sie es auf der Standardausgabe.
- Extrahieren Sie alle relevanten Zeilen
Wenn Ihre Eingabe durch Tabulatoren getrennt ist und Sie eine durch Tabulatoren getrennte Ausgabe wünschen, lautet der obige Code:
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
Anmerkungen:
- Leistung: Die Ausführungszeit für diesen Ansatz ist deutlich höher als die der
awk
basierten Lösungen (ich habe getestetroaimas Antwort). Zumindest um eine Größenordnung. - Andererseits funktioniert dieser Ansatz auch, wenn die Eingabedatei nicht geordnet ist.
- Obwohl diese Art von Lösung eine schnelle (und schmutzige?) Möglichkeit ist, die Arbeit effektiv zu erledigen, ist die Verarbeitung von Text mit Shell-Schleifen im Allgemeinen nicht ratsam; siehe als Referenz "Warum gilt die Verwendung einer Shell-Schleife zur Textverarbeitung als schlechte Praxis?".