Ich habe eine große Anzahl einzelner Dateien, die jeweils sechs Spalten enthalten (Anzahl der Zeilen kann variieren). Ein einfaches Beispiel:
1 0 0 0 0 0
0 1 1 1 0 0
Ich versuche herauszufinden, wie viele eindeutige Spalten ich habe (d. h. Zahlen und deren Reihenfolge stimmen überein), in diesem Fall wären es 3.
Gibt es dafür einen einfachen Einzeiler? Ich weiß, dass es einfach ist, eine Spalte mit einer anderen zu vergleichen, aber wie findet man identische Spalten?
Antwort1
Sie können die eindeutigen Spalten mit dem folgenden Pipe-Befehl zählen:
$ awk '{for (i=1; i<=NF; ++i) a[i]=a[i]$i; } END { for (i in a) print a[i] }' foo \
| sort -u | wc -l
Der awk-Befehl transponiert Ihre Eingabe, die resultierenden Zeilen werden sortiert, nur eindeutige Zeilen werden beibehalten ( -u
) und am Ende werden alle (eindeutigen) Zeilen (also die transponierten Spalten) gezählt ( wc -l
).
Beachten Sie, dass dies NF
eine integrierte awk-Variable ist und automatisch auf die Anzahl der Felder im aktuellen Datensatz gesetzt wird. $i
verweist auf das i-te Feld und END
schützt den folgenden Block so, dass er ausgeführt wird, nachdem alle Datensätze verarbeitet wurden. Awk verwendet standardmäßig die Feldtrennung zwischen Leer- und Nicht-Leerfeldern.
Antwort2
(((...))), aber wie findet man identische Spalten?
$ printf '%s\n' '1 0 0 0 0 0' '0 1 1 1 0 0' | awk -vSUBSEP='=' '
{ for (i=1; i<NF; i++)
for (j=i+1; j<=NF; j++)
if ($i==$j)
M[i,j]++
}
END{ for (m in M) if (M[m]==NR) print m }'
5=6
2=3
2=4
3=4
Inkrementieren Sie alle Spalten i<j
jeder Zeile, M[i,j]
wenn die Werte dieser Spalten gleich sind. M[i,j]==NR
Nach dem Lesen NR
der Zeilenmittelwerte waren die Werte für alle gelesenen Zeilen also identisch.
Antwort3
Diese Frage hat mich interessiert und ich wollte einen Ansatz verfolgen, den ich nicht genau herausfinden konnte und bekam wunderbare Hilfenachdem ich eine andere Frage gepostet habe. Den Ansatz, den ich zu verfolgen versuche, können Sie anhand der Frage verstehen, die ich gepostet habe.
Ich habe 2 weitere Lösungen für dieses Problem (eine vonGnoucsAntwort, die eineperlLösung und eine weitere von JohnsLösung kombiniert mit meiner Lösung).
#The variable appended_input will remove spaces/tabs and just append the rows.
#Modify the file name in this line. Here I use inputfile as the filename.
appended_input=$(column -s '\t' inputfile | tr -d '[:space:]') ;
#The array variable will store each column-wise value as an array element.
#I use sort to find the number of unique elements.
array=($(
for ((i=0; i<6; i++))
do
new=${appended_input:$i:1}
for ((j=i+6; j<${#appended_input}; j=j+6))
do
new="$new${appended_input:$j:1}"
done
echo "$new"
done
)) | echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Testen
Meine Eingabedatei ist wie unten.
1 0 0 1 0 0
0 1 1 0 0 0
1 1 1 1 1 0
1 0 0 1 0 1
1 0 0 1 0 1
Nach dem Ausführen des obigen Skripts erhalte ich die folgende Ausgabe:
00011 00100 01100 10111
Sie könnten eine wc -w
als letzte Pipe haben und würden als Ausgabe nur 4 erhalten, statt der eindeutigen Spaltenwerte wie oben.
Antwort4
Hier ist eine gawk
Lösung, die Coprozesse verwendet, um jede Spalte einer separaten Instanz von zuzuführen sha256sum
und die Gesamtzahl der eindeutigen Hashes angibt (die Anzahl der eindeutigen Hashes sollte mit der Anzahl der eindeutigen Spalten übereinstimmen, da die Wahrscheinlichkeit einer Hash-Kollision mit sha256sum
statistisch unbedeutend ist). Manche mögen dies für einen ungeheuerlichen Hack halten, aber dieser Ansatz hat gegenüber einigen anderen den Vorteil, dass er nicht versucht, die Daten zu verketten/transponieren und daher relativ speichereffizient ist.
awk 'BEGIN{for(i=1; i<=6; ++i){s=sprintf("%*s", i+1, ""); a[i]="sha256sum"s}}
{for (i=1; i<=6; ++i) print $i |& a[i]}
END{com= "sort | uniq | wc -l"
for (i=1; i<=6; ++i){close(a[i], "to"); a[i] |& getline x;
close(a[i]); print x | com};
close(com)}' file