So entfernen Sie doppelte Namen und drucken ein Array nach eindeutigen Namen

So entfernen Sie doppelte Namen und drucken ein Array nach eindeutigen Namen

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 \tin 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:
    • cutwählt nur den ersten Abschnitt ( -f 1) einer Zeile aus und unterbricht ihn an jedem Leerzeichen ( -d ' ');
    • sort | uniqsortiert 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 filemit grep;
    • 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.

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:

  1. Leistung: Die Ausführungszeit für diesen Ansatz ist deutlich höher als die der awkbasierten Lösungen (ich habe getestetroaimas Antwort). Zumindest um eine Größenordnung.
  2. Andererseits funktioniert dieser Ansatz auch, wenn die Eingabedatei nicht geordnet ist.
  3. 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?".

verwandte Informationen