CSV 文件:根据每个值的第一个模式对值进行分组和求和

CSV 文件:根据每个值的第一个模式对值进行分组和求和

我正在使用 bash 创建一个脚本来查找、分组和求和 CSV 文件中的字段。每行都有以逗号分隔的字段,每个字段都遵循类似的约定。对于每个逗号分隔的字段,都有一个数字值,然后是一个等号 (=),然后是一个字母数字值。 “(number)=”可能会或可能不会出现在一行中,如果出现,字段位置可能会有所不同,但在行中仅出现一次。另外,等号后面的值的长度也会有所不同。

我的目标的一个例子是最好的。 CSV 文件:

35=D,11=ABCD1,1=ABC,55=XYZ,38=100,40=P,18=M,54=1,59=0,10=111
35=D,11=ABCD2,1=ABC,55=XYZ,40=P,18=M,38=200,54=1,44=10.00,59=0,10=133
35=D,11=ABCD3,1=ABC,55=XYZ,40=P,18=M B,54=1,38=300,44=10.00,59=0,110=200,10=113
35=D,11=ABCD4,1=ABC,55=XYZ,38=400,40=P,18=M B F,54=1,44=10.00,59=0,110=300,10=144
35=D,11=ABCD5,1=ABC,55=ZYX,38=300,40=2,54=1,44=10.00,59=3,10=132
35=D,11=ABCD6,1=ABC,55=ZYX,38=100,40=1,18=C,54=2,59=3,10=131

我想要一个脚本来识别以“38=”开头的每个字段,然后对“=”后面的每个数值进行求和,并按每个“55=”进行分组。每行都会有一个“38=”和一个“55=”。

使用上述文件的输出将是(排序是可选的):

55=XYZ 38=1000
55=ZYX 38=400

答案1

使用米勒http://johnkerl.org/miller/doc,从此开始input.csv

35=D,11=ABCD1,1=ABC,55=XYZ,38=100,40=P,18=M,54=1,59=0,10=111 35=D,11=ABCD2,1=ABC,55=XYZ,40=P,18=M,38=200,54=1,44=10.00,59=0,10=133 35=D,11=ABCD3,1=ABC,55=XYZ,40=P,18=M B,54=1,38=300,44=10.00,59=0,110=200,10=113 35=D,11=ABCD4,1=ABC,55=XYZ,38=400,40=P,18=M B F,54=1,44=10.00,59=0,110=300,10=144 35=D,11=ABCD5,1=ABC,55=ZYX,38=300,40=2,54=1,44=10.00,59=3,10=132 35=D,11=ABCD6,1=ABC,55=ZYX,38=100,40=1,18=C,54=2,59=3,10=131

和跑步

mlr --ofs " " unsparsify then stats1 -a sum -f 38 -g 55 then rename 38_sum,38 input.csv

你将会拥有

55=XYZ 38=1000 55=ZYX 38=400

答案2

Steeldriver 有点打败了我,但我想出了

perl -F'[=,]' -lane '
        %row = @F;
        $sum{$row{55}} += $row{38};
    }{ 
        print "$_ = $sum{$_}" for keys %sum
' file.csv
XYZ = 1000
ZYX = 400

答案3

这是一个awk解决方案。

awk -F, '{for(a=1;a++<=NF;){
          if($a~/^55=/){l=$a}
          if($a~/^38=/){b[l]+=substr($a,4)}
         }}END{for(x in b){print x,"38="b[x]}}' inp
  • for(a=1;a++<=NF;){- 循环遍历每个逗号分隔的字段
  • if($a~/^55=/){l=$a}- 如果我们找到一个以 开头的字段,55=则将其存储在变量中l
  • if($a~/^38=/){b[l]+=substr($a,4)}- 如果我们找到一个以 开头的字段,则38=获取后面的值=并将其累积到 array 中b,使用变量l作为键
  • }}END{for(x in b){print x,"38="b[x]}}- 只打印数组的内容

答案4

怎么样

awk -F, '
        {for (i=1; i<=NF; i++)  {split ($i, T, "=")
                                 if (T[1] == 55) IX = T[2]
                                 if (T[1] == 38) NM = T[2]
                                }
         SUM[IX] += NM
        }
END     {for (s in SUM) print "55=" s, "38=" SUM[s]
        }
' file
55=ZYX 38=400
55=XYZ 38=1000

遍历所有字段以查找相关字段,拆分为T数组,如果55找到,则提取索引,如果38找到,则提取被加数。循环结束后,进行求和。在END部分中,显示所有汇总值及其索引。

相关内容