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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Perl的Hash of Hashes等效实现了Tcl中的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

... 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;
}

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

我尝试了一小段代码设置如下所示的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"
 }
}

谢谢。

答案

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

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

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

另一答案

不完全相同但有点相似:

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

以上是关于Perl的Hash of Hashes等效实现了Tcl中的dicts字典的主要内容,如果未能解决你的问题,请参考以下文章

perl学习hashes

每日学习:Perl语言学习之哈希(Hashes)

Redis常用命令--Hashes

redis之hashes类型及操作

C#Redis哈希Hashes

是否有与 Perl 的 WWW::Mechanize 等效的 PHP?