加载字段1并在Perl中的END {}等效awk处打印

时间:2017-09-28 16:44:21

标签: arrays perl awk foreach equivalent

我有以下AWK脚本,它计算字段1中元素的出现次数,当完成读取整个文件时,打印每个元素和重复次数。

awk '{a[$1]++} END{ for(i in a){print i"-->"a[i]} }' file

我对perl非常新,我不知道它是如何相同的。到目前为止我的内容如下,但语法不正确。提前谢谢。

perl -lane '$a{$F[1]}++ END{foreach $a {print $a} }' file

____________________________________ UPDATE ______________________________________

嗨,谢谢你的回答。实际输入文件有3400万行,awk和Perl之间的执行时间快3倍或更多。 awk比perl快吗?

awk '{a[$1]++}END{for(i in a){print i"-->"a[i]}}' file #--> 2:45 aprox
perl -lane '$a{$F[0]}++;END{foreach my $k (keys %a){ print "$k --> $a{$k}" } }' file #--> 7 min aprox
perl -lanE'$a{$F[0]}++; END { say "$_ => $a{$_}" for keys %a }' file # -->9 min aprox

5 个答案:

答案 0 :(得分:1)

相当于您的awk

perl -lanE'$a{$F[0]}++; END { say "$_ => $a{$_}" for keys %a }' file

-a,该行会分为@F中的字段,因此您希望$F[0]作为哈希%a中的键,其值由{{{}处理1}}。哈希在密钥上迭代并打印在++块中。

然而,效率比较出现了。改善这种情况的一种方法是不使用END获取线路上的所有字段,因为只需要第一个字段。在两种想到的方式之间

-a

perl -nE'$a{(/(\S+)/)[0]}++; END { ... }' 

{8}行文件的perl -nE'$a{(split " ", $_, 2)[0]}++; END { ... }' split的正则表达式明显加快了3.63s

对于4.41s行,这仍然落后1.99s。因此,awk 似乎更快完成此任务。

我的800万行文件的时间总结(几次运行的平均值)

awk  (question)  1.99s
perl (split)     3.63s
perl (regex)     4.41s
perl (like awk)  5.61s

这些时间相差几十毫秒(几个0.01秒)。

答案 1 :(得分:1)

输入文件显然会有所不同,但Perl 5.22.1在我的3350万行测试文件(12.23 vs 12.52秒)上略低于Awk 4.1.3。

schumack@daddyo2 10-02T18:25:17 54> wc -l listbig
33521910 listbig

schumack@daddyo2 10-02T18:25:58 55> /usr/bin/time -f '%E %P' awk '{a[$1]++} END{ for(i in a){print i"-->"a[i]} }' listbig
1-->9434310
2-->1605840
3-->9635040
4-->5218980
5-->4416060
7-->802920
8-->802920
9-->802920
12-->802920
0:12.52 99%

schumack@daddyo2 10-02T18:26:17 56> /usr/bin/time -f '%E %P' perl -lne '$_=~s/^(\S+) .*/$1/; $a{$_}++; END{foreach $i (keys %a){print "$i-->$a{$i}"}}' listbig 
1-->9434310
5-->4416060
2-->1605840
3-->9635040
12-->802920
8-->802920
9-->802920
4-->5218980
7-->802920
0:12.23 99%

答案 2 :(得分:1)

好的,Ger,还有一次:-) 我将我的Perl升级到我可用的最新版本并制作了一个类似你所描述的文件(在第1列和唯一列中每行有3450万行16位数字):

schumack@linux2 52> wc -l listbig
34521909 listbig

schumack@linux2 53> head -3 listbig
1111111111111111
3333333333333333
4444444444444444

然后我运行了一个专门的Perl行(适用于此文件,但与awk行不同)。和以前一样,我使用/ usr / bin / time定时运行:

schumack@linux2 54> /usr/bin/time -f '%E %P' /usr/local/bin/perl -lne 'chomp; $a{$_}++; END{foreach $i (keys %a){print "$i-->$a{$i}"}}' listbig
5555555555555555-->4547796
1111111111111111-->9715747
9999999999999999-->826872
3333333333333333-->9922465
1212121212121212-->826872
4444444444444444-->5374669
2222222222222222-->1653744
8888888888888888-->826872
7777777777777777-->826872
0:12.20 99%

schumack@linux2 55> /usr/bin/time -f '%E %P' awk '{a[$1]++} END{ for(i in a){print i"-->"a[i]} }' listbig
1111111111111111-->9715747
2222222222222222-->1653744
3333333333333333-->9922465
4444444444444444-->5374669
5555555555555555-->4547796
1212121212121212-->826872
7777777777777777-->826872
8888888888888888-->826872
9999999999999999-->826872
0:12.61 99%

perl和awk在3450万行文件上运行速度非常快,并且相距不到半秒。 好奇您目前使用的是什么类型的机器/ OS / Perl版本。我在华硕笔记本电脑上测试了大约4年,拥有英特尔I7。我使用的是Ubuntu 16.04和Perl v5.26.1

无论如何,感谢您使用Perl的理由!

玩得开心, 肯

答案 3 :(得分:0)

这种破坏性的方法是我提出的最快的方法:

perl -lne '$_=~s/\s.*//; $a{$_}++; END{foreach $i (keys %a){print "$i-->$a{$i}"}}' file

然而,它仍然不如awk快。

答案 4 :(得分:-1)

您可以浏览a2p

$ cat file
1
1
2
3
3
3

$ perl -lane '$a{$F[0]}++;END{foreach my $k (keys %a){ print "$k --> $a{$k}" } }' file
1 --> 2
2 --> 1
3 --> 3

$ awk '{a[$1]++} END{ for(i in a){print i" --> "a[i]} }' file
1 --> 2
2 --> 1
3 --> 3