awk:每列中每个 uniq 字符串的总数,并按相应的列顺序输出

awk:每列中每个 uniq 字符串的总数,并按相应的列顺序输出

我试图获取每列中每个 uniq 字符串的总计数(总和),并按相应的列顺序输出。

我需要在一个强大的 awk 命令中使用它,因为不同的完整输入通常是数千行和列。

我自己尝试过这样做,但没有任何运气。我想我已经很接近了,这就是我使用代码的地方,尽管它显然不起作用:

awk -F ',' '{ for(N=1; N<=NF; N++) {{count[$N]++} END {for (word in count) print word, count[word]}}}'

我对上述代码的想法是,如果我运行的话,我可以获得单个指定列的所需输出,现在让我们说第 2 列:

awk '{count[$2]++} END {for (word in count) print word, count[word]}'

但是我需要为每一列提供这种类型的输出。所以我试图循环遍历列来实现这一点,但它失败了:(

以下是一些示例数据:

输入示例:

M,M,M,M
N,N,N,N    
A,M,G,L
P,P,P,P
A,N,G,L    
P,N,P,L
A,A,A,A
C,C,C,C
A,M,G,C
L,L,L,L
G,G,G,G

相应的期望输出:

M 1,M 2,M 1,M 1
N 1,N 2,N 1,N 1
A 3,A 1,A 1,A 1
P 1,P 1,P 1,P 1
L 1,L 1,L 1,L 3
G 1,G 1,G 3,G 1
C 1,C 1,C 1,C 1

为了解释输出,示例输入中的第一列有 3 个 A,所有其他字母各只有 1 个,因此该列的输出为:
M 1
N 1
A 3
P 1
L 1
G 1
C 1

我编写了这段代码并且它可以工作,但理想情况下我想在 awk 命令中实现它:

for i in $(seq $NumberOfColumns);do
ColumnOutput=$(awk -F ',' -v x=$i '{count[$x]++} END {for (word in count) print word, count[word]}' file)
TotalOutput=$(paste <(echo "$TotalOutput") <(echo "$ColumnOutput") -d ,)
done    
echo "$TotalOutput" | sed 's/^,//g'    

答案1

我认为这会有所帮助:

$ awk -F"," '              
    NR==FNR { for (i=1;i<=NF;i++) {a[i,$i]+=1;b[$i]=$i} next }
    { for (i=1;i<=NF;i++)if(b[$1]) printf "%s %s,",$1,a[i,$1];else next; print ""; delete b[$1] }
' file file
M 1,M 3,M 1,M 1,
N 1,N 3,N 1,N 1,
A 4,A 1,A 1,A 1,
P 2,P 1,P 2,P 1,
C 1,C 1,C 1,C 2,
L 1,L 1,L 1,L 3,
G 1,G 1,G 4,G 1,

答案2

使用(以前称为 Perl_6)

~$ raku -e 'my @a = [Z] lines.map: *.split(","); my @b; \ 
            for ^@a -> $row  {                          \
                for ^$row.elems -> $col {    my %h;     \
                    %h{$_}++ for @a[$row]>>.[$col];     \
                    @b.push: %h.sort }};                \ 
            for ^@b>>.elems.max -> $j {                 \
                put @b.map({ $_.[$j] // (" " => "0") }).join: "," };'  file

或者(更简单):

~$ raku -e 'my @a = [Z] lines.map: *.split(","); my @b; \
            for ^@a -> $row {                           \
                my %h is BagHash = @a[$row];            \ 
                @b.push: %h.sort };                     \ 
            for ^@b>>.elems.max -> $j {                 \
                put @b.map({ $_.[$j] // (" " => "0") }).join: "," };'  file

以下是用 Raku(Perl 编程语言家族的成员)编写的答案。 Raku 具有对 Unicode 的内置高级支持。上面的代码利用了 Perl 系列功能,例如@-sigiled 数组和%-sigiled 哈希(即字典/键值对)。

  • 首先,使用 逐行读取数据lines,每个数据都split以逗号分隔。为了交换行和列,[Z]使用运算符,并将数据存储在@a数组中。

  • 接下来,@a数组将被迭代,首先是 by,$row然后是 by $col,以便对于每个$row单元格“key”( $_) 都存储在%h散列(第一个答案)或 BagHash(第二个答案)中。分析每一行后,键/值数据将存储在@b数组中。

  • 最后确定max键/值的数量(通过),并输出数据,注意在特定列的键可能未定义的地方插入零(OP 可以在此处使用,而不是):elemsput0"Nil"" "

示例输入(注意列中键的数量不相等):

M,M,M,M
N,N,N,N
A,M,G,L
P,P,P,P
A,N,G,L
P,N,P,L
A,A,A,A
C,C,C,C
A,M,G,X
L,L,L,L
G,G,G,G

示例输出(键/值对\t以制表符分隔):

A  4,A  1,A  1,A  1
C  1,C  1,C  1,C  1
G  1,G  1,G  4,G  1
L  1,L  1,L  1,L  4
M  1,M  3,M  1,M  1
N  1,N  3,N  1,N  1
P  2,P  1,P  2,P  1
   0,   0,   0,X  1

https://docs.raku.org/type/BagHash
https://docs.raku.org
https://raku.org

相关内容