我有一个如下所示的文件:
2017-07-30 A
2017-07-30 B
2017-07-30 B
2017-07-30 A
2017-07-30 A
2017-07-30 C
2017-07-31 A
2017-07-31 B
2017-07-31 C
2017-07-31 B
2017-07-31 C
每条线代表一个事件(A、B 或 C)及其发生的日期。我想计算每天每种类型的事件数量。这可以通过 完成sort file | uniq -c
,输出如下:
3 2017-07-30 A
2 2017-07-30 B
1 2017-07-30 C
1 2017-07-31 A
2 2017-07-31 B
2 2017-07-31 C
但是,我希望将每个事件类型作为一列:
A B C
2017-07-30 3 2 1
2017-07-31 1 2 2
有没有一个相当常见的命令行工具可以做到这一点?如果有必要,可以假设所有事件类型(A、B、C)都是预先已知的,但如果没有必要,那就更好了。同样,可以假设每个事件每天至少发生一次(意味着输出中没有零),但如果没有必要,这里也最好。
答案1
如果“相当常见”包括GNU 数据混合, 然后
datamash -Ws crosstab 1,2 < file
前任。
$ datamash -Ws crosstab 1,2 < file
A B C
2017-07-30 3 2 1
2017-07-31 1 2 2
(不幸的是,该网站的格式不保留制表符 - 实际输出是制表符对齐的)。
答案2
awk解决方案:
awk '{ d[$1]; k[$2]; a[$2,$1]++ }END{
printf("%10s"," ");
for(i in k) printf("\t%s",i); print "";
for(j in d) {
printf("%-10s",j);
for(i in k) printf("\t%d",a[i,j]); print ""
} }' file
输出:
A B C
2017-07-30 3 2 1
2017-07-31 1 2 2
答案3
较短的版本,我们不将空值分配为零:
perl -lane '
++$h{$i[!$h{$F[0]} ? @i : -1]=$F[0]}{$F[1]}}{
print join "\t", "\t", @h = sort keys %{ +{ map { map { $_ => 1 } keys %$_ } values %h } };
print join "\t", $_, @{$h{$_}}{@h} for @i;
' yourfile
perl -lane '
$i[@i]=$F[0] unless $h{$F[0]};
++$h{$F[0]}{$F[1]}}{
@h = sort keys %{ +{ map { map { $_ => 1 } keys %$_ } values %h } };
print join "\t", "\t", @h;
for my $date ( @i ) {
my $href = $h{$date};
print join "\t", $date, map { $href->{$_} || 0 } @h;
}
' yourfile
结果
A B C
2017-07-30 3 2 1
2017-07-31 1 2 2
数据结构:
%h
包含keys
日期和值的哈希值 子哈希值的键为 A、B、C 等,相应的值是它们在这些特定日期上各自的计数。
%h = (
2017-07-30 => {
A => 3,
B => 2,
C => 1,
},
...
);
@i
按遇到的顺序存储日期的数组。@i
仅当之前未见过或第一次看到时,我们才会将日期推入数组。顺序由数组位置提供。@h
将哈希中的所有“A”、“B”、“C”等键相加后,数组具有唯一键%h
。
答案4
用法: ./count.awk input.txt | column -t -n
#!/usr/bin/gawk -f
{
dates[$1] = $1;
events[$2] = $2;
numbers[$1][$2]++;
}
END {
num_dates=asort(dates);
num_events=asort(events);
for (i = 1; i <= num_events; i++) {
printf " %s", events[i];
}
print "";
for (i = 1; i <= num_dates; i++ ) {
printf "%s ", dates[i];
for (j = 1; j <= num_events; j++) {
printf "%s ", numbers[dates[i]][events[j]];
}
print "";
}
}
测试:
输入(测试复杂)
2017-07-30 A
2017-07-30 D
2017-07-29 D
2017-07-30 B
2017-07-28 E
2017-07-30 B
2017-07-30 A
2017-07-30 A
2017-07-30 C
2017-07-31 A
2017-07-31 B
2017-07-31 C
2017-07-31 B
2017-07-31 C
输出
A B C D E
2017-07-28 1
2017-07-29 1
2017-07-30 3 2 1 1
2017-07-31 1 2 2