按键按排序顺序处理Perl哈希

时间:2018-10-26 13:01:45

标签: perl hash

我有一个使用哈希的Perl脚本,其中的内容是UUID,键是XML文本元素。 XML文本元素使用普通排序合理地排序。

在处理每个元素时,我将其写入日志文件。相关代码如下:

use 5.016;
open(my $loghandle, '>', 'process.log') or die "Couldn't open logfile";

%XMLhash = (
      'e01af02f-e8e5-476e-a250-e70c3925463a' => '<Form><AUni ws="fr">retirer</AUni></Form>',
      '8187b534-a8c8-4e14-bf0b-1bd9cfada31e' => '<Form><AUni ws="fr">pencher</AUni></Form>',
      '1848c7a2-c2f8-4884-8327-c0f1a9da7a4b' => '<Form><AUni ws="en">repair</AUni></Form>',
      'b36c127c-91b2-41db-96ec-18c172ad9917' => '<Form><AUni ws="fr">fou</AUni></Form>',
      'abb4e9dc-dc66-43b5-951e-e720e21da286' => '<Form><AUni ws="en">four</AUni></Form>',
      '8cf707e6-e0a1-4611-bb28-ff18d2de38db' => '<Form><AUni ws="en">robust</AUni></Form>',
    );

while( my( $guid, $XMLtext ) = each %XMLhash ) {
    my $somestuff = 'What I did', # some process that tells what I did 
    say $loghandle "Text:$XMLtext Guid:$guid I did $somestuff";
    }

及其生成的日志文件(每次运行的顺序可能不同):

Text:<Form><AUni ws="en">robust</AUni></Form> Guid:8cf707e6-e0a1-4611-bb28-ff18d2de38db I did:What I did
Text:<Form><AUni ws="en">four</AUni></Form> Guid:abb4e9dc-dc66-43b5-951e-e720e21da286 I did:What I did
Text:<Form><AUni ws="fr">retirer</AUni></Form> Guid:e01af02f-e8e5-476e-a250-e70c3925463a I did:What I did
Text:<Form><AUni ws="fr">fou</AUni></Form> Guid:b36c127c-91b2-41db-96ec-18c172ad9917 I did:What I did
Text:<Form><AUni ws="en">repair</AUni></Form> Guid:1848c7a2-c2f8-4884-8327-c0f1a9da7a4b I did:What I did
Text:<Form><AUni ws="fr">pencher</AUni></Form> Guid:8187b534-a8c8-4e14-bf0b-1bd9cfada31e I did:What I did

我希望日志文件按XML文本(即哈希键)排序。

我尝试将while语句更改为:

while( my( $guid, $XMLtext ) = each sort keys %XMLhash ) {

这给了我一个错误:“每个引用对象的参数类型必须是...处的无哈希值hashref或arrayref”。

要获得排序的日志文件,我可以按键顺序处理哈希吗?

在我当前的解决方法中,我将日志写入一个数组,对该数组进行排序,然后将该数组写入日志文件。在我看来,这不是最佳选择。

1 个答案:

答案 0 :(得分:1)

请勿为此使用each。它仅适用于散列(以及较新的Perls中的数组)。使用常规的foreach并按值排序。

foreach my $key ( sort { $xml{$a} cmp $xml{$b} } keys %xml ) {
  say "$key: $xml{$key}";
}

您需要获取键,然后对值进行排序,因为这就是XML东西所在的位置。

如果要先按文本节点排序,然后按ws属性对单个文本节点进行排序,则会变得更加复杂。

foreach my $key ( map { $_->[0] }
                  sort { $a->[2] cmp $b->[2] || $a->[1] cmp $b->[1] }
                  map { [ $_, $xml{$_} =~ m/"(..)">([^<]+)</ ] } keys %xml
) {
  say "$key: $xml{$key}";
}

这利用了所谓的Schwartzian transform,后者执行一次昂贵的操作,将要存储的结果存储在上面,然后将原始数据放回原处。由于您的XML代码段始终具有相同的格式,因此使用正则表达式提取要排序的数据会节省很多时间。