使用哈希perl存储行号和每个单词的出现次数



我正在逐字读取文件(其中文件包含单词行)并将每个单词存储在哈希中。 我想存储出现次数以及在哪一行找到单词(注意:我将根据单词本身对哈希进行排序,如代码所示)

我有(不工作)(假设单词数组正确存储了单词,没有特殊字符,并且是小写的):

my %wordlist;
my $line = 0;
foreach my $word (@words) {
  $line++;
  if (exists $wordlist{$word}) {
      $wordlist{$word} += 1;
      $wordlist{$line} = $wordlist{$line} . ", $line";
  }
  else {
      $wordlist{$word} = 1;
      $wordlist{$line} = "$line";
  }  
}

后来我尝试将 $wordlist{$line} 打印为字符串,在一个包含以下内容的循环中:

printf "%${length}s: %4d times, on lines %sn", $key, $wordlist{$key}, $wordlist{$line};

运行时,出现错误:

Use of uninitialized value in printf at ./wc.pl line 105, <FILE> line 20.
someWord:    2 time(s), line(s) 

其中第 20 行是退出语句

$wordlist{$line}   # Line data for each line

应该是

$wordline{$word}   # Line data for each word

在输出

之前格式化输出通常是一种不好的做法。这里也不例外。

if (exists $wordlist{$word}) {
    ++$wordlist{$word};
    push @{ $wordline{$word} }, $line;
}
else {
    ++$wordlist{$word};
    push @{ $wordline{$word} }, $line;
}

这当然简化为

++$wordlist{$word};
push @{ $wordline{$word} }, $line;

printf中,您将使用

join(', ', @{ $wordline{$word} })

$wordlist{$word}只是@{ $wordline{$word} }中的元素数量,所以完全不需要。只需使用

0+@{ $wordline{$word} }

而不是

$wordlist{$word}

所以你最终得到

use strict;
use warnings;
use List::Util qw( max );
my %wordlines;
while (<>) {
   chomp;
   push @{ $wordlines{$_} }, $.;
}
my $max_len_p1 = 1 + max map length, keys %wordlines;
my $max_count_len = max map length(0+@$_), values %wordlines;
my $format = "%-${max_len_p1}s %${max_count_len}d times, on lines %sn";
for my $word (
   sort { @{ $wordlines{$b} } <=> @{ $wordlines{$a} } || $a cmp $b }
      keys %wordlines
) {
   printf($format,
      "$word:",
      0+@{ $wordlines{$word} },
      join(', ', @{ $wordlines{$word} }),
   );
}

输入:

cat
house
stair
chari
stair
mouse
stool
cat
hat

输出:

cat:   2 times, on lines 1, 8
stair: 2 times, on lines 3, 5
chari: 1 times, on lines 4
hat:   1 times, on lines 9
house: 1 times, on lines 2
mouse: 1 times, on lines 6
stool: 1 times, on lines 7

你可以试试下面的例子,它应该给你一个很好的基础来开始和修改。

use strict;
use warnings;
my @words = <>;
my %wordlist;
my $line = 0;
foreach my $word (@words) {
        chomp($word);
        push (@{$wordlist{$word}}, ++$line);
}
foreach my $word (keys %wordlist){
        my $count = @{$wordlist{$word}};
        my $lines = join (', ',@{$wordlist{$word}});
        printf ("%-10s: %4d times, on lines %sn", $word, $count, $lines);
}

此示例使用 perls 自存活来动态创建数据结构(如果尚未定义)。从本质上讲,它读取的每个单词都会将行号推送到哈希中该单词键的数组中。如果该单词从未出现过,则 autovivifaction 将在哈希中创建键,并在哈希值中创建数组。

然后对于输出,我们可以得到单词,因为它是键,我们可以通过计算哈希值数组中存在的行号数量来获得它被看到的次数,我们可以使用 join 制作一串行号。

然后我们可以用 printf 打印出这些值。 所以一个单词列表

cat
house
stair
chari
stair
mouse
stool
cat
hat

将产生

mouse     :    1 times, on lines 6
cat       :    2 times, on lines 1, 8
hat       :    1 times, on lines 9
stool     :    1 times, on lines 7
chari     :    1 times, on lines 4
stair     :    2 times, on lines 3, 5
house     :    1 times, on lines 2

最新更新