首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于平板的awk计数和和:

基于平板的awk计数和和:
EN

Stack Overflow用户
提问于 2014-06-27 13:24:47
回答 2查看 215关注 0票数 1

希望从第一个文件(GunZip *.gz i.e Input.csv.gz)中提取所有行,如果第一个文件第4字段位于第二个文件(Slab.csv)第一个字段(开始范围)和第二个字段(结束范围)的范围内,则填充Slab明智的行计数以及第一个文件的第4和第5个字段的和。

Input.csv.gz (GunZip)

代码语言:javascript
复制
Desc,Date,Zone,Duration,Calls
AB,01-06-2014,XYZ,450,3
AB,01-06-2014,XYZ,642,3
AB,01-06-2014,XYZ,0,0
AB,01-06-2014,XYZ,205,3
AB,01-06-2014,XYZ,98,1
AB,01-06-2014,XYZ,455,1
AB,01-06-2014,XYZ,120,1
AB,01-06-2014,XYZ,0,0
AB,01-06-2014,XYZ,193,1
AB,01-06-2014,XYZ,0,0
AB,01-06-2014,XYZ,161,2

Slab.csv

代码语言:javascript
复制
StartRange,EndRange
0,0
1,10
11,100
101,200
201,300
301,400
401,500
501,10000

预期产出:

代码语言:javascript
复制
StartRange,EndRange,Count,Sum-4,Sum-5
0,0,3,0,0
1,10,NotFound,NotFound,NotFound
11,100,1,98,1
101,200,3,474,4
201,300,1,205,3
301,400,NotFound,NotFound,NotFound
401,500,2,905,4
501,10000,1,642,3

我使用以下两个命令来获得上面的输出,期望得到“NotFound”情况。

代码语言:javascript
复制
awk -F, 'NR==FNR{s[NR]=$1;e[NR]=$2;c[NR]=$0;n++;next} {for(i=1;i<=n;i++) if($4>=s[i]&&$4<=e[i]) {print $0,","c[i];break}}' Slab.csv <(gzip -dc Input.csv.gz) >Op_step1.csv
cat Op_step1.csv | awk -F, '{key=$6","$7;++a[key];b[key]=b[key]+$4;c[key]=c[key]+$5} END{for(i in a)print i","a[i]","b[i]","c[i]}' >Op_step2.csv

Op_step2.csv

代码语言:javascript
复制
101,200,3,474,4
501,10000,1,642,3
0,0,3,0,0
401,500,2,905,4
11,100,1,98,1
201,300,1,205,3

任何建议,使它成为一个班轮命令,以实现预期的输出,不要有perl,python访问。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-06-27 14:06:35

下面是使用awksort的一种方法:

代码语言:javascript
复制
awk '
BEGIN { 
    FS = OFS = SUBSEP = ",";
    print "StartRange,EndRange,Count,Sum-4,Sum-5" 
} 
FNR == 1 { next }
NR == FNR {
    ranges[$1,$2]++;
    next
}
{
    for (range in ranges) {
        split(range, tmp, SUBSEP); 
        if ($4 >= tmp[1] && $4 <= tmp[2]) {
            count[range]++;
            sum4[range]+=$4;
            sum5[range]+=$5; 
            next
        }
    }
}
END {
    for(range in ranges) 
        print range, (count[range]?count[range]:"NotFound"), (sum4[range]?sum4[range]:"NotFound"), (sum5[range]?sum5[range]:"NotFound") | "sort -t, -nk1,2"
}' slab input
StartRange,EndRange,Count,Sum-4,Sum-5
0,0,3,NotFound,NotFound
1,10,NotFound,NotFound,NotFound
11,100,1,98,1
101,200,3,474,4
201,300,1,205,3
301,400,NotFound,NotFound,NotFound
401,500,2,905,4
501,10000,1,642,3
  • 将输入、输出字段分隔符和SUBSEP设置为,。打印标题行。
  • 如果是第一行,跳过它。
  • 将整个slab.txt加载到名为ranges的数组中。
  • 对于ranges数组中的每个区域,拆分字段以获得开始和结束范围。如果第4列在此范围内,则增加计数数组,并适当地将值添加到sum4sum5数组中。
  • END块中,遍历范围并打印它们。
  • 将输出输送到sort,以便按顺序得到输出。
票数 2
EN

Stack Overflow用户

发布于 2014-06-27 15:35:57

下面是另一个使用perl的选项,它利用了创建多维数组和散列的好处。

代码语言:javascript
复制
perl -F, -lane'
BEGIN {
    $x = pop; 
    ## Create array of arrays from start and end ranges
    ## $range = ( [0,0] , [1,10] ... )
    (undef, @range)= map { chomp; [split /,/] } <>; 
    @ARGV = $x;
}
## Skip the first line
next if $. ==1; 
## Create hash of hash
## $line = '[0,0]' => { "count" => counts , "sum4" => sum_of_col4 , "sum5" => sum_of_col5 }
for (@range) { 
  if ($F[3] >= $_->[0] && $F[3] <= $_->[1]) { 
    $line{"@$_"}{"count"}++; 
    $line{"@$_"}{"sum4"} +=$F[3]; 
    $line{"@$_"}{"sum5"} +=$F[4];
  } 
} 
}{ 
  print "StartRange,EndRange,Count,Sum-4,Sum-5"; 
  print join ",", @$_, 
  $line{"@$_"}{"count"} //"NotFound",  
  $line{"@$_"}{"sum4"}  //"NotFound", 
  $line{"@$_"}{"sum5"}  //"NotFound" 
    for @range
' slab input
StartRange,EndRange,Count,Sum-4,Sum-5
0,0,3,0,0
1,10,NotFound,NotFound,NotFound
11,100,1,98,1
101,200,3,474,4
201,300,1,205,3
301,400,NotFound,NotFound,NotFound
401,500,2,905,4
501,10000,1,642,3
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24452972

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档