2017-06-27 1 views
-3

Zum Beispiel habe ich eine Datei:Wie man mehrere Zeichenfolgen mit einem Schlüssel zusammenfasst?

key1 1212 
key2 1212 
key1 32332 
key2 3232 
key2 3232 

Ich möchte Datei erhalten:

key1 1212,32332 
key2 1212,3232,3232 
+0

dies in bash möglich sein soll, aber ich würde vorschlagen, anstatt Ihr Gehirn zu brechen - bessere Tools verwenden, wenn Sie bash fragen - es Linux - hat definitiv python - benutze es - und die Aufgabe wird einfach. – Drako

+0

awk und python-Tags aufgrund von Kommentaren zu meiner Antwort hinzugefügt. –

Antwort

1

In awk:

$ awk '{a[$1]=a[$1](a[$1]==""?"":",")$2}END{for(i in a)print i,a[i]}' file 
key1 1212,32332 
key2 1212,3232,3232 

Erklärt:

awk '{          # use awk for this kind of stuff 
    a[$1]=a[$1] (a[$1]=="" ? "" : ",") $2 # hash on first col and append seconds 
} 
END {           # after everything is hashed 
    for(i in a)        # for each entry in hash a 
     print i,a[i]       # output key and data 
}' file          # oh yeah the file 

Edit: Anstatt awk tun die Pufferung (dh. Hashing zu a) könnten wir sort verwenden, um die Datei zu sortieren und dann den Schlüssel und alle Daten danach kommasepariert auszugeben. awk für den letzten Teil wieder verwendet:

$ sort file | awk '$1!=p{printf "%s%s",(NR>1?ORS:""),$1}{printf "%s%s", ($1==p?",":OFS),$2;p=$1}END{print ""}' 
key1 1212,32332 
key2 1212,3232,3232 

Hier sort ist keine Phantasie Parameter nicht gegeben, aber in der realen Welt benötigt werden, um einige könnten. Die awk Teil erklärt:

sort file | \       # sort the file 
awk '         # before feeding to awk 
$1!=p {        # if key is different from previous key 
    printf "%s%s",(NR>1?ORS:""),$1  # newline and print the key 
} 
{ 
    printf "%s%s", ($1==p?",":OFS),$2 # print the data comma-separated 
    p=$1        # store key for comparing on the next round 
} 
END{ 
    print ""       # finish the last line nicely 
}' 
+0

antwort höchstwahrscheinlich ist gut und funktioniert, aber ich versuche immer auch zu halten people parasieren textdateien mit bash - es ist ineffizient. und Sie wissen nicht, wie groß diese Eingabedatei ist, so kann es wirklich schlecht sein :), und Bdfy, unter Berücksichtigung Ihrer SO-Reputation - wenn Sie Tag Python zu Ihrer Frage hinzufügen, werde ich arbeiten Python-Lösung, die ich denke ist besser zu benutzen als bash. – Drako

+0

@Drako: Having said, 'awk' ist völlig in Ordnung für kleine Dateien – sjsam

+1

@SJSAM Ich stimme zu, aber wenn die Eingabe wird 500MB oder mehr werden Sie wirklich mehr mit Python-Lösung glücklich :) deshalb, auch für kleine tendiere ich dazu Verwenden Sie die richtigen Tools, wenn möglich, weil Sie nie wissen, wann es wachsen kann :) – Drako

0
awk '{a[$1]=(a[$1]!="")?a[$1]","$2:$2}END{for(i in a){print i "\t" a[i]}}' file 
key1 1212,32332 
key2 1212,3232,3232 

sollte es tun.

0

Wenn Sie vermeiden möchten, die Ergebnisse für die gesamte Datei zu puffern (z. B. wenn die Datei sehr groß ist), könnten Sie sort und Pythons itertools.groupby verwenden. Erstellen Sie ein Python-Skript wie folgt aus:

# group.py 

import itertools, sys 

for k, g in itertools.groupby(sys.stdin, lambda x: x.split()[0]): 
    print(k, ",".join([x.split()[1] for x in g])) 

Dann laufen:

sort file | python group.py 
key1 1212,32332 
key2 1212,3232,3232 

Ansonsten diese schnelle Perl Einzeiler sollte auch funktionieren, indem Sie Werte in einem Hash Akkumulieren:

perl -aE 'push @{$h{$F[0]}}, $F[1]; END {$"= ","; say "$_ @{$h{$_}}" for sort keys %h}' file 

Ausgabe:

key1 1212,32332 
key2 1212,3232,3232 
0

es ist nicht rein sh/coreutils, betrachtet aber datamash für diese Aufgabe mit:

sed -r -e 's/[[:space:]]+/ /g' < infile.txt | datamash -t ' ' -s groupby 1 collapse 2 
Verwandte Themen