打印 3 列数据文件中“键”的出现次数和相关“值”的总和

打印 3 列数据文件中“键”的出现次数和相关“值”的总和

我正在使用 shell 读取 Redis 转储文件。

转储文件中有 3 个主要列,如下所示。

Text:tags:name    682651    520
Text:tags:age     78262     450
Value:cache       77272     672
Value:cache:name  76258     872
New:specific      77628     762
New:test          76628     8622

预期输出:

Key     Count     Sum
Text:*  2         970
Value:* 2         1544
New:*   2         9384

希望获得上述预期,因为可以根据子字符串检查列,可能会以字符串(键)开头/中间/结尾。

答案1

以下awk程序将执行该任务:

awk '{split($1,f,/:/);count[f[1]]++;sum[f[1]]+=$3}
     END{printf "Key\tCount\tSum\n"; for (k in count) {printf "%s:*\t%d\t%d\n",k,count[k],sum[k]}}' dump.txt
  • 这将首先将第 1 列的键拆分为:多个组件,然后将其存储在数组中f。第一个条目 ( f[1]) 被视为所有进一步处理的相关键。
  • 出现次数将存储在一个关联数组中count,以键f[1]作为数组索引。每次找到密钥时它都会加 1。
  • 第 3 列中的值的总和类似地存储在关联数组中sum
  • 最后,程序打印标题行,然后迭代数组中找到的所有数组索引,count以打印数组索引(= 键)、出现次数和求和值。

请注意,打印键的顺序是由awk存储数组的内部逻辑定义的。如果您有 GNU Awk,则可以PROCINFO["sorted_in"]BEGIN节中设置属性来定义遍历顺序。例如

BEGIN{PROCINFO["sorted_in"]="@ind_str_asc"}

将使awk按“键”的字典顺序升序打印条目。

答案2

首先修改第一个字段,以便第一个字段之后的所有内容:都替换为*

awk -v OFS='\t' '{ sub(":.*", ":*", $1) }; 1' file

此命令通过将扩展正则表达式的第一个匹配项替换为文字字符串 来awk修改第一个空格分隔字段。根据您的数据,其输出将是以下制表符分隔的数据::.*:*

Text:*  682651  520
Text:*  78262   450
Value:* 77272   672
Value:* 76258   872
New:*   77628   762
New:*   76628   8622

然后,我们可以按第一个制表符分隔字段对其进行分组,同时计算每组中折叠的行数并对第三个字段求和。一种方法是使用 GNU datamash

awk -v OFS='\t' '{ sub(":.*", ":*", $1) }; 1' file |
datamash groupby 1 count 1 sum 3

awk如果原始输入未排序,则要么传递数据sort,要么使用datamash-s选项。

这将输出以下内容(以制表符分隔):

Text:*  2       970
Value:* 2       1544
New:*   2       9384

要输出标头,只需首先调用

printf '%s\t%s\t%s\n' 'Key' 'Count' 'Sum'

完整的事情,读取file和写入一些新文件output

{
    printf '%s\t%s\t%s\n' 'Key' 'Count' 'Sum'
    awk -v OFS='\t' '{ sub(":.*", ":*", $1) }; 1' |
    datamash groupby 1 count 1 sum 3
} <file >output

答案3

$ awk -F'[:[:space:]]+' '
    { cnt[$1]++; sum[$1]+=$NF }
    END {
        print "Key", "Count", "Sum"
        for (key in cnt) {
            print key":*", cnt[key], sum[key]
        }
    }
' file | column -t
Key      Count  Sum
Value:*  2      1544
Text:*   2      970
New:*    2      9384

答案4

使用(以前称为 Perl_6)

~$ raku -e 'my (@k, @v); given lines.map(*.words).list {  \
            @k = .map(*.[0].split(":").[0]); @v = .map(*.[2]) };  \
            my %count1 = Bag(@k); my %agg1.=append: [Z=>] @k, @v;  \
            my %sum1; for %agg1 { %sum1.append: $_.key => [+] $_.value };  \
            for ([Z] %count1.sort, %sum1.sort) {  \
            say .[0].key ~qb[\t]~ .[0].value ~qb[\t]~ .[1].value};' file

输入示例:

Text:tags:name    682651    520
Text:tags:age     78262     450
Value:cache       77272     672
Value:cache:name  76258     872
New:specific      77628     762
New:test          76628     8622

示例输出:

New     2   9384
Text    2   970
Value   2   1544

该解决方案利用了所有 Perl 系列语言中存在的哈希功能,这里专门用 Raku 编写。

简而言之,lines被读入,并且每一行被分成以空格分隔的wordsmap这是指示 Raku 在“每个”行元素内工作的内容)。数据被保存到包含冒号@k后第一个字符串元素的数组中,以及仅包含第三列(零索引 = 2)的数组中。此时数组看起来像这样:split@v

#Add this statement:
.say for @k, @v;

#Returns:
[Text Text Value Value New New]
[520 450 672 872 762 8622]

Raku 有一个Bag()内置函数,它给出每个键的出现次数(计数)(使用行my %count1 = Bag(@k);)。

从这里%agg1创建一个聚合哈希,它“压缩”@k@v列,=>将它们配对在一起,并将append它们放入哈希中%agg1。当然,散列的一个属性是每个key都是唯一的,因此values与相同的散列相关联key被放置为构成每个键的数组元素value。此时%agg1哈希看起来像这样:

#Add this statement:
.say for %agg1.sort;

#Returns:
New => [762 8622]
Text => [520 450]
Value => [672 872]

%agg1然后再次迭代该哈希以创建哈希,该哈希(您猜对了)以明智的方式%sum1对个体求和。最后,输出数据,用制表符分隔(引号制表符减少了代码中对双引号的需要),并通过波形符完成字符串连接。valueskey~qb[\t]~\t~

https://andrewshitov.com/2020/03/16/a- Couple-of-syntax-sweets-in-raku/
https://youtu.be/wViVLytlwb8
https://raku.org

相关内容