Avas Roy
Avas Roy

Reputation: 11

Partial pattern matching for elements that are in two lists in TCL

So, lets say I have these two lists as below:

ListA contains:

{{feed_sesmmu1_qmusharemem_se_smmu0_int}
{feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_datvld}
{feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_dat[31]}
{feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_dat[30]} 
{feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_dat[29]}
{feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_dat[28]}
{feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_dat[27]}
{feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_dat[26]}}

and ListB:

{{se_smmu0_int}
{se_smmu0_soc_rd_datvld}
{se_smmu0_soc_rd_dat[29]}
{se_smmu0_soc_rd_dat[31]}
{se_smmu0_soc_rd_dat[30]}
{se_smmu0_soc_rd_dat[28]} 
{se_smmu0_soc_rd_dat[26]}
{se_smmu0_soc_rd_dat[27]}}

Now I need {feed_sesmmu1_qmusharemem_se_smmu0_soc_rd_dat[27]} to match {se_smmu0_soc_rd_dat[27]} and other elements of listA should match their counterparts in listB.

Upvotes: 1

Views: 676

Answers (2)

Peter Lewerin
Peter Lewerin

Reputation: 13252

You can do it with

lmap s $ListB {
    lsearch -inline $listA *[string map {[ \\[ ] \\]} $s]
}

The idea is to take each item in the list ListB and search for that item in the list listA. There are to caveats: some of the items in ListB have brackets ([ ]) in them, and those characters are special to the glob search that lsearch uses by default. So we will escape them: string map {[ \\[ ] \\]} $s. Also, the item from ListB is going to be a suffix in listA, so we need to prepend a star, * for "any character".

If you don't have lmap and don't want to use the drop-in replacement in the lmap (for Tcl 8.5) link:

set result {}
foreach s $ListB {
    lappend result [lsearch -inline $listA *[string map {[ \\[ ] \\]} $s]]
}
puts $result

Documentation: foreach, lappend, lmap (for Tcl 8.5), lmap, lsearch, puts, set, string

Syntax of Tcl string matching:

  • * matches a sequence of zero or more characters
  • ? matches a single character
  • [chars] matches a single character in the set given by chars (^ does not negate; a range can be given as a-z)
  • \x matches the character x, even if that character is special (one of *?[]\)

Upvotes: 1

Flopp
Flopp

Reputation: 1947

Here's a solution with explicit foreach loops, in case lmap is not available. It also avoids glob-style string matching if favor of a range-based match:

proc endsWidth {s suffix} {
    set index end-[expr {[string length $suffix]-1}]
    return [expr {[string range $s $index end] eq $suffix}]
}

foreach b $listB {
    foreach a $listA {
        if {[endsWidth $a $b]} {
            puts "$a $b"
        }
    }
}

Upvotes: 0

Related Questions