Dictionary Perl';Tcl中dict的Hash等价实现

Dictionary Perl';Tcl中dict的Hash等价实现,dictionary,hash,nested,tcl,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/pe

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

*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;
}
但这似乎不起作用。我对它进行了如下测试:

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

谢谢。

不完全一样,但有些相似:

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

您眼前的问题是正则表达式开头的斜杠

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

dict set foo aa bb cc 1
设置字典中的成员
{cc 1}
,该成员是
foo
中的成员
{bb…}
的值

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

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”的存在

回到圣经的圣经

*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
    }
}
文件:

请注意,这不是“散列”,而是一个具有复杂键的单级关联数组。请注意,Tcl不支持多维键。上面第一项的关键是
*1)(RES)(L1)(N1
。它仍然有效,但使用的格式意味着一些不存在的功能。我将使用与
不同的分隔符。)(
。逗号、破折号、句点都很好。如果需要对键进行排序,则应仔细选择键的格式。Peter,很抱歉,我在原始问题中复制/粘贴时出错。对于Tcl部分,正则表达式应该是:`If[regexp{^\s*(\s+)\s+(RES|CAP|IND)\s+(\s+)(\s+)(\s+)\s+)\s*}$line…`如果您在查询数据时做了一些非常复杂的事情,那么将其转储到内存中的SQLite数据库是很容易的。嗨,多纳尔,有没有关于如何将Tcl与内存中的SQLite一起使用的文档?我想试试看我是否可以继续使用该解决方案。谢谢。@user3512999:我不知道最好的文档是什么,但h你看过这里吗
set found 0
dict for {key subdict} $dod {
    if {[dict exists $subdict RES]} {
        set found 1
        break
    }
}