首页 文章

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

提问于
浏览
2

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

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 回答

  • 1

    首先,我不明白为什么你要使用一个模块来保持你的哈希顺序 . 我假设您希望按时间戳字段排序输出,并且您从输入文件中读取的数据已经按此顺序排序,但是对普通散列的键进行排序并按顺序打印内容很简单而不依赖对传入的数据进行预分类

    您已经阅读了解释为什么您的代码没有按预期运行的原因 . 这就是我如何编写一个希望行为正常的解决方案(尽管除了检查它编译之外我还没能测试它)

    我选择使用双元素数组来代替散列,以包含每个时间戳的询价和出价 . 这应该使代码运行速度更快,并使其更简单,更容易阅读

    还值得注意的是,我添加了 use autodie ,这使得perl会自动检查IO操作的状态,例如 openchdir ,并消除手动编码这些检查所造成的混乱 . 我还为文件根目录的路径定义了一个常量,并使用 chdir 在那里设置工作目录 . 这消除了重复路径的这一部分并减少剩余文件路径字符串的长度的需要

    #!/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;
    
  • 2

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

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

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

    但是当您使用 Hash::Ordered 对象时,您的脚本还会使用您在第一个 foreach 循环中使用 $dict_lead->get($key) 填充的纯数据结构( %hash ) . 在这种情况下,所有用于向哈希添加键的常规技术,习惯用法和规则仍然适用 . 您不希望将嵌套的哈希值从 $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"
    

    还有其他方法可以“深度”将一个嵌套数据结构的一部分复制到另一个嵌套数据结构(请参阅下面的Stackoverflow参考),您也许可以避免一起使用临时变量,但这些小的更改可能是您需要的所有必要条件 . 案件 .


    通常,为了"insert another hash as a value for ... keys",您需要使用引用或匿名哈希构造函数( { k => "v" , ... } ) . 所以例如添加一个键:

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

    Output

    ("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 ;
    

    Output

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

    参考文献

相关问题