如何计算与搜索词对应的每列的每个条目

时间:2015-06-08 15:47:34

标签: perl

我有一个像这样的输入文件(3列数据)。每行中也存在不同的条目..对应于... b ..和c ...

a   sk  asd                 
a   sk  lsd                 
a   mk  wsd                 
a   lk  asd                 
a   lk  lsd                 
a   pk  wsd                 
a   pk  asd                 
b   sk  lsd                 
b   sk  wsd                 
b   mk  asd                 
b   lk  lsd                 
b   lk  wsd                 
c   sk  asd                 
c   sk  lsd                 
c   mk  wsd                 
c   lk  asd                 
c   lk  lsd                 
d   sk  wsd                 
d   sk  asd                 
d   mk  lsd

我想编写一个perl程序,首先计算a,b,c和d。然后计算对应于a,b,c和d的每个条目。

输出将是这样的..

a=7 sk=2    mk=1    lk=2    pk=2    asd=3   lsd=2   wsd=2    
b=5 sk=2    mk=1    lk=2    pk=0    asd=1   lsd=2   wsd=2    
c=5 sk=2    mk=1    lk=2    pk=0    asd=2   lsd=2   wsd=1
d=3 sk=2    mk=1    lk=0    pk=0    asd=1   lsd=1   wsd=1

我怎么能做到这一点。请帮帮忙?

1 个答案:

答案 0 :(得分:1)

像这样:

#!/usr/bin/perl 
use strict;
use warnings;

my %count_elements_of;
my %count_of;

while (<DATA>) {
    my ( $term, @things ) = split;
    $count_of{$term}++;
    foreach my $thing (@things) {
        $count_elements_of{$term}{$thing}++;
    }
}

foreach my $term ( sort keys %count_elements_of ) {
    print "$term => $count_of{$term}, ";
    foreach my $thing ( sort keys %{ $count_elements_of{$term} } ) {
        print "$thing => $count_elements_of{$term}{$thing}, ";
    }
    print "\n";
}


__DATA__
a sk asd
a sk lsd
a mk wsd
a lk asd
a lk lsd
a pk wsd
a pk asd
b sk lsd
b sk wsd
b mk asd
b lk lsd
b lk wsd
c sk asd
c sk lsd
c mk wsd
c lk asd
c lk lsd
d sk wsd
d sk asd
d mk lsd

将打印:

a => 7, asd => 3, lk => 2, lsd => 2, mk => 1, pk => 2, sk => 2, wsd => 2, 
b => 5, asd => 1, lk => 2, lsd => 2, mk => 1, sk => 2, wsd => 2, 
c => 5, asd => 2, lk => 2, lsd => 2, mk => 1, sk => 2, wsd => 1, 
d => 3, asd => 1, lsd => 1, mk => 1, sk => 2, wsd => 1, 

要解释 - 你需要的是哈希,这实际上是perl&#39;杀手级功能之一。我们在上面的例子中有两个,因为你想计算两个不同的东西 - 第一个字母的出现,以及该字母前缀中每个子元素的出现。

  • 所以我们遍历DATA的每一行(你可能想在这里使用一个真正的文件句柄)。

  • 我们使用split将行转换为数组,以空格分隔。

  • 我们将第一个元素分配给$term,并将该行中的所有其他内容分配到@things

  • 迭代@things列表,并更新特定字母内的总计数,以及每个前缀/字母%count_elements_of哈希值。

  • 然后我们迭代哈希的键(对它们进行排序)并打印结果。

我们在上面做的不是特别好地处理完全丢失的键。如果你想这样做,你就不能再在哈希上使用keys - 因为&#39;不存在&#39;未定义&#39;。

相反,你需要:

#!/usr/bin/perl 
use strict;
use warnings;

my %count_elements_of;
my %count_of;
my %all_sub_elements; 

while (<DATA>) {
    my ( $term, @things ) = split;
    $count_of{$term}++;
    foreach my $thing (@things) {
        $count_elements_of{$term}{$thing}++;
        $all_sub_elements{$thing}++; 
    }
}

foreach my $term ( sort keys %count_elements_of ) {
    print "$term => $count_of{$term}, ";
    foreach my $thing ( sort keys %all_sub_elements ) {
        print "$thing => ", $count_elements_of{$term}{$thing} // 0," ";
    }
    print "\n";
}

这将构建&#39;在%all_sub_elements中可能需要打印的所有内容的列表,我们稍后会使用它来确定要输出的内容。我们使用//运算符,这是一个条件类似||(逻辑或),但用于defined。在这种情况下它没有太大的区别,但我认为在正常操作哈希时它是一个有用的区别。 (因为值为零的哈希值与具有缺失值的哈希值相同)。

然后打印:

a => 7, asd => 3 lk => 2 lsd => 2 mk => 1 pk => 2 sk => 2 wsd => 2 
b => 5, asd => 1 lk => 2 lsd => 2 mk => 1 pk => 0 sk => 2 wsd => 2 
c => 5, asd => 2 lk => 2 lsd => 2 mk => 1 pk => 0 sk => 2 wsd => 1 
d => 3, asd => 1 lk => 0 lsd => 1 mk => 1 pk => 0 sk => 2 wsd => 1 

你可以 - 或者 - 定义一个数组:

my @output_order = qw ( sk lk mk asd lsd wsd );

如果您愿意,可以使用它来输出您的输出:

foreach my $thing ( @output_order ) {