在 TCL 中以有效的方式在列表中搜索部分模式



简介:(不一定需要回答我的问题,但可能会有所帮助)

我有一个块,里面有多个块(儿子)。 对于每个这样的块(或子块),我正在读取其DEF(设计交换格式)文件并将其所有实例名称分配给一个列表。 因此,我从我读取的所有 DEF 文件中创建了一个包含所有实例名称的列表。 此外,我有一个 primeTime 会话,其中包含块中的所有实例(包括"儿子"块)。

我的问题

如何在列表中高效搜索部分实例名称?

阐述:

假设我有一个名为DefInstsLst的列表,其中包含数千个实例名称(如简介中所述,从 DEF 文件中读取)。 例如,此列表包含以下实例名称:

DRO_TAP_31__ap_dro_tap/keep_dro_nr

现在,从 primeTime 读取的顶部块的完整实例名称如下:

ld_top_dft_top/dro_cluster/genblk1_DRO_PACK_0__ap_dro_pack/genblk1_5__DRO_TEL_ap_dro_cell_5nm_7t_TEL/ap_dro_v2_cell/DRO_CELL_DRO_TEL_ap_dro_delay_5nm_7t_TEL/DRO_TAP_31__ap_dro_tap/keep_dro_nd

现在我想根据它的后缀DRO_TAP_31__ap_dro_tap/keep_dro_nd在我的列表中找到这个实例DefInstsLst,但由于它是一个巨大的列表,所以我必须有效地搜索它(我正在对 primeTime 会话中的每个实例进行这种搜索)。 我尝试使用lsort命令对列表进行排序,然后lsearch -sorted有效地搜索,但是当使用标志-sorted时,我无法搜索部分模式,而只能搜索完全匹配。 当搜索名称完全匹配的实例时,我用lsearch描述的方式在运行时方面非常有效。

由于您正在寻找后缀,因此您没有任何选择比不涉及大量准备工作的lsearch -glob *$pattern更有效。排序无济于事,因为这是从字符串的开头开始的。该 glob(前面有一个*)的效率与您进行单个字符串检查的效率一样高;它是球形匹配机械中优化的案例之一。

你可能做的准备工作?准备另一个列表,这些值全部颠倒并对其进行排序。然后,您可以在开头查找反向模式,这是可以通过二叉搜索有效地完成的(这正是lsearch -sorted所做的)。这可能是很多开销!或者,您可以拆分字符串以提取某种排序规则键;它的适用性取决于您正在寻找的内容。这两者都有很多开销;每个列表条目都会获得额外的数据,可能与列表条目本身一样大。(如果有很多,请考虑使用数据库;SQLite非常出色,并且与Tcl集成得很好。

我同意Donal的观点,一些准备工作可能是你最好的选择。 以不同的方式重新排列所有数据,使其在此类搜索中更有效。

例如,您可以遍历所有实例名称,并按后缀将它们排列到字典中:

set suffix_dict [dict create]
foreach instance_name $instance_names {
# Assume the suffix are the last two parts full hierarchical instance name
set suffix [join [lrange [split $instance_name "/"] end-1 end] "/"]
dict lappend suffix_dict $suffix $instance_name
}
set suffix_lookup "DRO_TAP_31__ap_dro_tap/keep_dro_nr"
set matching_instances [dict get $suffix_dict $suffix_lookup]

准备字典是一次性成本,但之后是快速的字典查找。

另一个想法是将lsearch命令放入进程。 每次调用 proc 时,都会缓存 args 的结果。

set cache [dict create]
proc lookup_instance {pattern} {
# Check cache first
if {[dict exists $::cache $pattern]} {
return [dict get $::cache $pattern]
}
set matches [lsearch -sorted -all -inline $::instance_names]
# Save to cache
dict set ::cache $pattern $matches
return $matches
}

如果您经常查找相同的模式,这将节省时间。

最新更新