哈希的有序哈希 - 设置和访问键/值对

时间:2015-06-25 12:17:56

标签: perl data-structures hash associative-array perl-data-structures

我想实现一个有序哈希,其中每个键值对的值将是另一个嵌套哈希映射。我无法这样做。我没有收到任何错误,但没有打印出来。

use Hash::Ordered;
use constant { lead_ID => 44671 , lag_ID => 11536 , start_time => time };

my $dict_lead=Hash::Ordered->new;
my $dict_lag=Hash::Ordered->new;

open(my $f1,"<","tcs_07may_nse_fo") or die "cant open input file";
open(my $f2,">","bid_ask_".&lead_ID) or die "cant open output file";
open(my $f3,">","ema_data/bid_ask_".&lag_ID) or die "cant open output file";

while(my $line =<$f1>){
    my @data=split(/,/,$line);
    chomp(@data);
    my ($tstamp, $instr) = (int($data[0]), $data[1]); 
    if($instr==&lead_ID){
      $dict_lead->set($tstamp=>{"bid"=>$data[5],"ask"=>$data[6]});
    }
    if($instr==&lag_ID){
      $dict_lag->set($tstamp=>{"bid"=>$data[5],"ask"=>$data[6]});
    }
}
close $f1;
foreach my $key ($dict_lead->keys){
    my $spread=$dict_lead{$key}{"ask"}-$dict_lead{$key}{"bid"};
    %hash=$dict_lead->get($key);
    print $key.",".$hash{"ask"}."\n";
    print $f2 $key.",".$dict_lead{$key}{"bid"}.","
          .$dict_lead{$key}{"ask"}.",".$spread."\n";
}
foreach my $key ($dict_lag->keys){
    my $spread=$dict_lag{$key}{"ask"}-$dict_lag{$key}{"bid"};
    print $f3 $key.",".$dict_lag{$key}{"bid"}.","
          .$dict_lag{$key}{"ask"}.",".$spread."\n";
}
close $f2;
close $f3;
print "Ring destroyed in " , time() - &start_time   , " seconds\n";

我的终端上打印的输出是:

1430992791,  
1430992792,  
1430992793,  
1430992794,  
1430992795,  
1430992796,  
1430992797,  
1430992798,  
1430992799,  
Ring destroyed in 24 seconds

我从输出的第一列中意识到我能够在有序哈希中插入密钥。但我不明白如何插入另一个哈希作为这些键的值。另外,在迭代哈希的键时,如何访问这些值?

与文件句柄$f2对应的文件中的输出为:

1430970394,,,0  
1430970395,,,0  
1430970396,,,0  
1430970397,,,0  
1430970398,,,0  
1430970399,,,0  
1430970400,,,0  

2 个答案:

答案 0 :(得分:2)

First of all, I don't see why you want to use a module that keeps your hash in order. I presume you want your output ordered by the timestamp fields, and the data that you are reading from the input file is already ordered like that, but it would be simple to sort the keys of an ordinary hash and print the contents in order without relying on the incoming data being presorted You have read an explanation of why your code isn't behaving as it should. This is how I would write a solution that hopefully behaves properly (although I haven't been able to test it beyond checking that it compiles) Instead of a hash, I have chosen to use a two-element array to contain the ask and bid prices for each timestamp. That should make the code run fractionally faster as well as making it simpler and easier to read It's also noteworthy that I have added use autodie, which makes perl check the status of IO operations such as open and chdir automatically and removes the clutter caused by coding those checks manually. I have also defined a constant for the path to the root directory of the files, and used chdir to set the working directory there. That removes the need to repeat that part of the path and reduces the length of the remaining file path strings #!/usr/bin/perl use strict; use warnings; use 5.010; use autodie; use Hash::Ordered; use constant DIR => '../tcs_nse_fo_merged'; use constant LEAD_ID => 44671; use constant LAG_ID => 11536; chdir DIR; my $dict_lead = Hash::Ordered->new; my $dict_lag = Hash::Ordered->new; { open my $fh, '<', 'tcs_07may_nse_fo'; while ( <$fh> ) { chomp; my @data = split /,/; my $tstamp = int $data[0]; my $instr = $data[1]; if ( $instr == LEAD_ID ) { $dict_lead->set( $tstamp => [ @data[5,6] ] ); } elsif ( $instr == LAG_ID ) { $dict_lag->set( $tstamp => [ @data[5,6] ] ); } } } { my $file = 'ema_data/bid_ask_' . LEAD_ID; open my $out_fh, '>', $file; for my $key ( $dict_lead->keys ) { my $val = $dict_lead->get($key); my ($ask, $bid) = @$val; my $spread = $ask - $bid; print join(',', $key, $ask), "\n"; print $out_fh join(',', $key, $bid, $ask, $spread), "\n"; } } { my $file = 'ema_data/bid_ask_' . LAG_ID; open my $out_fh, '>', $file; for my $key ( $dict_lag->keys ) { my $val = $dict_lead->get($key); my ($ask, $bid) = @$val; my $spread = $ask - $bid; print $out_fh join(',', $key, $bid, $ask, $spread), "\n"; } } printf "Ring destroyed in %d seconds\n", time - $^T;

答案 1 :(得分:1)

使用Hash::Ordered构造有序哈希,哈希是一个对象。这些对象具有属性(例如一个索引;如果你检查一个Hash::Ordered对象,它将不仅仅包含哈希元素),它们提供了操作和访问数据的方法。因此,您需要使用supplied methods - like set来访问哈希,就像您在此行中所做的那样:

$dict_lead->set($tstamp=>{"bid"=>$data[5],"ask"=>$data[6]});

使用标量$tstamp创建密钥,然后将其与匿名哈希值相关联。

但是当您使用Hash::Ordered个对象时,您的脚本还会使用您在第一个%hash中使用$dict_lead->get($key)填充的纯数据结构(foreach)环。在这种情况下,所有用于向哈希添加键的常规技巧,习惯用法和规则仍然适用。您不想在此处将$dict_lead Hash::Ordered对象中的嵌套哈希重复复制到%hash,您希望将嵌套哈希添加到%hash并将其关联用一把独特的钥匙。

如果没有要测试的样本数据或者要比较的预期输出的描述很难确定,但您可能只需要更改:

 %hash=$dict_lead->get($key);

类似于:

  $hash{$key} = $dict_lead->get($key); 

正确填充您的临时%hash。或者,由于每个键的值都是嵌套的匿名哈希值,因此您可能希望尝试将print $key.",".$hash{"ask"}."\n";更改为:

  print $key.",".$hash{$key}{"ask"}."\n"

还有其他方法可以深深地&#34;将一个嵌套数据结构的一部分复制到另一个嵌套数据结构(请参阅下面的Stackoverflow参考),您可以避免一起使用临时变量,但这些小的更改可能就是您所需的全部内容。

通常,为了&#34;插入另一个哈希作为...键的值#34;您需要使用引用或匿名哈希构造函数({ k => "v" , ... })。所以例如添加一个密钥:

my %sample_hash ;
$sample_hash{"key_0"} = { bid => "1000000" , timestamp => 1435242285 }; 
dd %sample_hash ;

<强>输出

("key_0", { bid => 1000000, timestamp => 1435242285 })

多个键从一个哈希添加到另一个哈希:

my %to_add = ( key_1 => { bid => "1500000" , timestamp => 1435242395 }, 
               key_2 => { bid => "2000000" , timestamp => 1435244898 } );

for my $key ( keys %to_add ) {  
   $sample_hash{$key} = $to_add{$key}  
}

dd %sample_hash ;

<强>输出

(
  "key_1",
  { bid => 1000000, timestamp => 1435242285 },
  "key_0",
  { bid => 1400000, timestamp => 1435242395 },
  "key_2",
  { bid => 2000000, timestamp => 1435244898 },
)

参考