내 파일에는 100개의 열이 포함되어 있습니다.
다음을 수행해야 합니다.
- 먼저 각 열의 중복 항목 수를 계산합니다.
- 그런 다음 행 수(최대에서 최소)별로 출력 열 순서를 표시합니다.
입력 파일:
a b c d e
11 11 22 56 11
11 44 56 89 11
12 56 78 91 11
22 60 78 11
22 60 91
60 98
91
91
95
결과물 파일:
b c a d e
11 22 11(2) 56 11(4)
44 56 12 89
56 78(2) 22(2) 91
60(3) 91
91(2) 98
95
답변1
GNU awk fo를 사용하는 배열의 배열 합계 sorted_in
:
$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == 1 {
numCols = split($0,tags)
next
}
{
for ( colNr=1; colNr<=NF; colNr++ ) {
val = $colNr
if ( val != "" ) {
if ( !seen[colNr][val]++ ) {
++colRowNrs[colNr]
}
rowNr = colRowNrs[colNr]
numRows = ( rowNr > numRows ? rowNr : numRows )
rowColVals[rowNr][colNr] = val
rowColCnts[rowNr][colNr]++
}
}
}
END {
PROCINFO["sorted_in"] = "@val_num_desc"
for ( colNr in colRowNrs ) {
tag = tags[colNr]
printf "%s%s", tag, (colNr<numCols ? OFS : ORS)
}
for ( rowNr=1; rowNr<=numRows; rowNr++ ) {
for ( colNr in colRowNrs ) {
val = rowColVals[rowNr][colNr]
cnt = rowColCnts[rowNr][colNr]
printf "%s%s%s", val, (cnt > 1 ? "("cnt")" : ""), (colNr<numCols ? OFS : ORS)
}
}
}
$ awk -f tst.awk file
b c a d e
11 22 11(2) 56 11(4)
44 56 12 89
56 78(2) 22(2) 91
60(3) 91
91(2) 98
95
위 내용은 입력 내용이 탭으로 구분되어 있다고 가정합니다. 이것이 잘못된 경우 질문을 편집하여 명확히 하십시오.
답변2
Linux 유틸리티를 사용하는 한 가지 방법이 여기에 나와 있습니다.
if="$PWD/file"
tmp=$(mktemp -d) || exit
cd -- "$tmp"
nf=$(awk -F '\t' '{print NF;exit}' "$if")
printf -v fmt '%%0%dd\n' "$(expr "$nf" : '.*')"
for i in $(seq "$nf"); do
cut -f"$i" "$if" |
grep -E '[^[:space:]]' |
uniq -c | awk '{$0 = $2 \
($1>1 ? "("$1")" : "")}1' \
> "$(printf "$fmt" "$i")"
done
wc -l * | sed 's/^\s*//;$d' |
sort -k1,1nr -k2 |
cut -d" " -f2 |
sed -e '${y/\n/\t/;q;}' -e 'N;H;z;x;D' |
xargs -l paste | column-t
산출:
b c a d e
11 22 11(2) 56 11(4)
44 56 12 89
56 78(2) 22(2) 91
60(3) 91
91(2) 98
95
답변3
Perl 데이터 구조를 사용하여 이 문제를 해결할 수 있습니다.
perl -F'/\t/,$_,-1' -lane '
$.==1 && do{
@hdr = @F; next;
};
for (0..$#F) {
my $e = $F[$_];
next if $e eq "";
my $main_key = $hdr[$_];
$h{$main_key}{$e}++;
}
}{
my @AoA =
map {
my $key = $hdr[$_];
my $href = $h{$key};
local($a,$b);
[
$key,
map {
my $k = $href->{$_};
$k > 1 ? qq[$_($k)] : $_;
}
sort {
$a <=> $b
}
keys %$href
]
}
sort {
keys %{$h{$hdr[$b]}} <=>
keys %{$h{$hdr[$a]}} ||
$a <=> $b
}
0..$#hdr;
# output
local $, = "\t";
for (my $i=0; $AoA[0][$i] ne ""; $i++) {
print map($AoA[$_][$i],0..$#AoA)
}
' file
산출:
b c a d e
11 22 11(2) 56 11(4)
44 56 12 89
56 78(2) 22(2) 91
60(3) 91
91(2) 98
95
답변4
열이 행이 되도록 테이블을 바꾸면 작업이 더 쉬워집니다. rs
예를 들어 BSD를 사용하여 이 작업을 수행할 수 있습니다.
< yourfile unexpand -t6 | # convert to tsv assumming 6-column wide columns
rs -nTc | # transpose
gawk -v OFS='\t' '{
c=0
for (i=j=2;++j<=NF+1;)
if ($i == $j"")
c++
else{
if (c++) $i=$i"("c")"
$++i=$j
c=0
}
print NF=--i,$0
}' |
sort -rn |
cut -f2- |
rs -nTc