Perl的Hash of Hashes等效实现了Tcl中的dicts dict

时间:2017-12-31 04:50:37

标签: dictionary hash nested tcl

我有一个非常大的文件,其中包含如下数据:

*1 RES L1 N1 0.32
*22 RES L2 N2 0.64

*100 CAP A1 B1 0.3
*200 CAP A2 B1 0.11

*11 IND K1 K2 0.002
*44 IND X1 Y1 0.00134

... and so on

对于这样的文件(让我们假设上面的数据在一个名为" example.txt"的文件中),我可以轻松地在Perl中创建一个哈希哈希并将这些嵌套的哈希传递给我的其他部分Perl程序:

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

open(FILE,"<", "example.txt") or die "Cannot open file:$!";
if (-f "example.txt") {
 while(<FILE>) {
  chomp;
  if(/^\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/) {
   $hoh{$1}{$2}{$3}{$4} = $5;
  }
 }
 close FILE;
}

创建一个哈希哈希(或者更确切地说是字典词典)的类似方法是什么?

我尝试了一小段代码设置下面的dict(不在此处打印完整代码,以便继续关注问题):

  ...
  set dod [dict create]

  if [regexp {^\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)\s*$} $line all id type x y elemValue] {
   dict set dod $id $type $x $y $elemValue
  }

但这似乎不起作用。我测试了它如下:

foreach id [dict keys $dod] {
 if [dict exists $dod "RES"] {
  puts "RES KEY EXISTS"
 } else {
  puts "RES KEY NOT FOUND"
 }
}

感谢。

2 个答案:

答案 0 :(得分:2)

你的直接问题是正则表达式开头的一个杂散斜杠。

回答这个问题:多键词典 是“哈希哈希”。每个键都会添加一个新级别的词典。

dict set foo aa bb cc 1

在字典中设置成员{cc 1},该字典是字典中成员{bb ...}的值,它是{aa ...}中成员foo的值。

如果想要一个多级字典,但仍需要使用多个键值,则需要执行以下操作:

dict set foo [list aa bb cc] 1

此外,我不知道您的示例中有多少简化,但添加项目的代码可以更好地说明:

if {[lindex $line 1] in {RES CAP IND}} {
    dict set dod {*}$line
}

但是如果你想通过例如检查存在“RES”,您需要将其设置为顶级键,您不在示例中(第一列中的项目将成为顶级键)。如上所述初始化,dod的值为

*1 {RES {L1 {N1 0.32}}} *22 {RES {L2 {N2 0.64}}} *100 {CAP {A1 {B1 0.3}}} *200 {CAP {A2 {B1 0.11}}} *11 {IND {K1 {K2 0.002}}} *44 {IND {X1 {Y1 0.00134}}}

所以你得到一本字典,但dict exists $dod RES仍然是假的。使用

if {[lindex $line 1] in {RES CAP IND}} {
    dict set dod {*}[lrange $line 1 end]
}

(即第一个作为键之后的行中的所有项目,除了最后一个成为值)你得到字典

RES {L1 {N1 0.32} L2 {N2 0.64}} CAP {A1 {B1 0.3} A2 {B1 0.11}} IND {K1 {K2 0.002} X1 {Y1 0.00134}}

您可以测试“RES”的存在。

回到dict-of-dicts

*1 {RES {L1 {N1 0.32}}} *22 {RES {L2 {N2 0.64}}} *100 {CAP {A1 {B1 0.3}}} *200 {CAP {A2 {B1 0.11}}} *11 {IND {K1 {K2 0.002}}} *44 {IND {X1 {Y1 0.00134}}}

您可以通过检查每个子词典来检查“RES”,直到找到具有该键的词典:

set found 0
dict for {key subdict} $dod {
    if {[dict exists $subdict RES]} {
        set found 1
        break
    }
}

文档: dict

答案 1 :(得分:1)

不完全相同但有些类似:

set data "*1 RES L1 N1 0.32
*22 RES L2 N2 0.64

*100 CAP A1 B1 0.3
*200 CAP A2 B1 0.11

*11 IND K1 K2 0.002
*44 IND X1 Y1 0.00134
"

set pattern {\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)?\s*$}
set result [regexp -all -line -inline -- $pattern $data]

if {[llength $result] == 0} {
    puts "Not found"
    exit 1
}

array set my_data {}
foreach {all ind_0 ind_1 ind_2 ind_3 ind_4} $result {
    set my_data($ind_0)($ind_1)($ind_2)($ind_3) $ind_4
}
puts [parray my_data]

示例输出:

my_data(*1)(RES)(L1)(N1)   = 0.32
my_data(*100)(CAP)(A1)(B1) = 0.3
my_data(*11)(IND)(K1)(K2)  = 0.002
my_data(*200)(CAP)(A2)(B1) = 0.11
my_data(*22)(RES)(L2)(N2)  = 0.64
my_data(*44)(IND)(X1)(Y1)  = 0.00134