Eindeutiges Sortieren aus einer Zeile

Eindeutiges Sortieren aus einer Zeile

Können Sie mir bitte einen Vorschlag machen, wie ich eine eindeutige Sortierung aus einer Zeile oder einem Satz machen kann? Ich habe Informationen wie diese:

Special   c1,c2,c5,c7,c1,c2   
Special2  C6

(das ist ein TAB-Zeichen zwischen Specialund c1...).

Ich möchte die Ausgabe folgendermaßen:

Special   c1,c2,c5,c7  
Special2  C6

Wie kann ich das erreichen?

Antwort1

Verwenden vondiese Antwort,

perl -MList::MoreUtils=uniq -laF'\t' -ne '
    $F[1] = join(",", uniq(sort(split(",", $F[1])))); print join("\t", @F)'

Dies hängt von einem externen Paket abList::WeitereDienstprogrammeWenn Sie keine externe Abhängigkeit installieren möchten, uniqist die Neuimplementierung der Funktionnur noch ein paar Zeilen Perl. (Obwohl es bei mir anscheinend als Teil des Basissystems auf macOS installiert ist.)

Antwort2

perl -F'\t|,' -lane 'my %h; print shift @F, "\t", join ",", sort grep !$h{$_}++, @F' dataf

Erläuterung

  • -F'\t|,'=> teilt jedes Datensatzfeld in das Array @Fnach TABZeichen auf comma.
  • -lwird auch „ RSzu newline“ und „ ORSbis“ festlegen .newline
  • -ateilt jeden Datensatz automatisch in Wörter auf, basierend auf der FSAuswahl von -F.
  • -nrichtet eine implizite Datensatz-Leseschleife für die Eingabe ein ANDund druckt Dinge nur auf Aufforderung.
  • -eist der PerlCode, der für jeden Datensatz der Eingabe basierend auf der oben getroffenen RSAuswahl ausgeführt werden soll -l.
  • Das erste Element wird durch angegeben shiftund die restlichen Elemente uniquifieddurch Speichern als Schlüssel eines Hashs, %hder bei jedem Einlesen eines Datensatzes neu generiert werden soll. Die eindeutigen Elemente werden dann sortiert, mit einem Komma verbunden und gedruckt.

Antwort3

Getestet mit OpenBSD awk, GNU awkund mawk:

awk -F ',| +' '{ for (i = 2; i <= NF; ++i) { print $1, $i } }' data.in |
sort -u |
awk '{ f[$1] = (f[$1] ? f[$1] "," : "") $2 } END { for (k in f) { print k, f[k] } }'

Die erste awkerweitert die gegebenen Daten in

Special c1
Special c2
Special c5
Special c7
Special c1
Special c2
Special2 C6

Es verwendet sowohl Kommas als auch mehrere Leerzeichen als Feldtrennzeichen und druckt für jeden Datensatz (Zeile) der Eingabe das erste Feld, gefolgt von jedem der anderen Felder nacheinander in separaten Zeilen. Dies setzt voraus, dass in den Zeilen keine anderen Leerzeichen oder Kommas vorhanden sind als dort, wo sie richtig als Trennzeichen interpretiert werden.

Der sortin der Mitte sortiert es in

Special2 C6
Special c1
Special c2
Special c5
Special c7

Es führt eine Sortierung durch, wobei die vollständige Zeile als Sortierschlüssel verwendet wird, und verwirft alle doppelten Zeilen.

Der letzte awkrekombiniert die Daten in

Special c1,c2,c5,c7
Special2 C6

Dies geschieht, indem das erste Feld als Schlüssel in ein assoziatives Array verwendet wird und die durch Kommas getrennte Verkettung der entsprechenden Daten im zweiten Feld als Wert gespeichert wird. Am Ende werden alle gesammelten Daten ausgedruckt.

Antwort4

Ein anderer Weg in einer Zeile:

while read line; do echo "$line" | awk '{print $1}' | tr '\n' ' ';  echo "$line" | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',' | sed -e 's/.$//g'; echo; done < file_to_sort

Es nimmt die erste Spalte jeder Zeile ( echo $line | awk '{print $1}' | tr '\n' ' ';) und sortiert die Werte der zweiten Spalte, getrennt durch „,“, nachdem es sie zur Anwendung in eine einzelne Spalte umgewandelt sortund sie dann wieder in eine einzelne Zeile mit der ursprünglichen Formatierung zurückkonvertiert hat ( echo $line | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',').

Zeilenaufteilung wie von @tripleee vorgeschlagen durchführen:

while IFS=$'\t' read first second; do printf "%s\t%s\n" "$first" "$(tr ',' '\n' <<<"$second" | sort | tr '\n' ',' | sed -e 's/.$//g';)"; done < file_to_sort

verwandte Informationen