TCL计算映射

  • 本文关键字:映射 计算 TCL tcl
  • 更新时间 :
  • 英文 :


我有一个包含映射的列表,如下

# {from, to, count}
{{XD} PD 2}
{{XB} PB 4}
{{XA0, XA1} PA 4}

如何使用TCL创建从[XD, XB, XA0, XA1]到[PD, PB, PA]的映射

Expected
# XD   XB   XA0  XA1
{{PD0  PB0  PA0  PA1}
{ PD0  PB0  PA2  PA3}
{ PD0  PB1  PA0  PA1}
{ PD0  PB1  PA2  PA3}
{ PD0  PB2  PA0  PA1}
{ PD0  PB2  PA2  PA3}
{ PD0  PB3  PA0  PA1}
{ PD0  PB3  PA2  PA3}

{ PD1  PB0  PA0  PA1}
{ PD1  PB0  PA2  PA3}
....}

这个特殊的问题最好是递归地处理。特别是,生成特定计数器的计数,然后导致回调以处理链中的下一个计数器。要按正确的顺序将结果拼凑在一起需要一点小心(有几种方法可以做到这一点),但下面的方法很好,因为它将数据生成为列表的列表,允许进一步处理它或根据您的选择进行漂亮的打印。

注意使用默认实参开始递归。通过使用包装器过程也可以不这样做,但这是一种改进。

proc genseq {definition {current {}}} {
    # Get the next part of the definition
    lassign [lindex $definition 0] columns prefix limit
    set definition [lrange $definition 1 end]
    set result {}
    for {set i 0} {$i < $limit} {} {
        # Handle the appending of bits relating to the counter at the current level
        set cur $current
        foreach c $columns {
            lappend cur "$prefix$i"
            incr i
        }
        # If we have more definition to process, recursive call. Otherwise just accumulate
        if {[llength $definition] > 0} {
            lappend result {*}[genseq $definition $cur]
        } else {
            lappend result $cur
        }
    }
    return $result
}

让我们测试一下:

set seqinfo {
    {{XD} PD 2}
    {{XB} PB 4}
    {{XA0 XA1} PA 4}
}
# A bit of trickery to get approximately the right output format
puts {{[join [genseq $seqinfo] "}n{"]}}

产生这个输出。

<>之前{{pd0 pb0 pa0 pa1}{pd0 pb0 pa2 pa3}{pd0 pb1 pa0 pa1}{pd0 pb1 pa2 pa3}{pd0 pb2 pa0 pa1}{pd0 pb2 pa2 pa3}{pd0 pb3 pa0 pa1}{pd0 pb3 pa2 pa3}{pd1 pb0 pa0 pa1}{pd1 pb0 pa2 pa3}{pd1 pb1 pa0 pa1}{pd1 pb1 pa2 pa3}{pd1 pb2 pa0 pa1}{pd1 pb2 pa2 pa3}{pd1 pb3 pa0 pa1}{pd1 pb3 pa2 pa3}}之前

我将把放置标题和额外的空格行作为练习。(另外,Tcl不会用逗号分隔列表;实际上,逗号是普通字符,在表达式之外没有什么特别之处。

我看了想要的输出,觉得它看起来很像一组关系值的笛卡尔积。因此,本着用大锤杀苍蝇的精神,您可以使用Tcl的关系代数扩展TclRAL (http://chiselapp.com/user/mangoa01/repository/tclral/index),并使用关系:

 package require ral
 # The original format of the spec.
 set mapspec {
    {XD PD 2}
    {XB PB 4}
    {{XA0 XA1} PA 4}
  }
# Way too much code required to convert from
# the original data to a set of relation values.
foreach spec $mapspec {
    lassign $spec attrs body count
    set heading [list]
    foreach attr $attrs {
        lappend heading $attr string
    }
    set tuples [list]
    for {set i 0} {$i < $count} {} {
        set tuple [list]
        foreach attr $attrs {
            lappend tuple $attr $body$i
            incr i ; # assume count % [llength $attrs] == 0
            # puts "tuple = $tuple"
        }
        lappend tuples $tuple
        # puts "tuples = $tuples"
    }
    set rel [ral relation create $heading {*}$tuples]
    # puts [ral relformat $rel rel]
    lappend rels $rel
}
# The "real work" is a one liner.
set prod [ral relation times {*}$rels]
# Print the result as a table.
puts [ral relformat $prod "Mapping as a relation value"]

+------+------+------+------+
|XD    |XB    |XA0   |XA1   |
|string|string|string|string|
+------+------+------+------+
|PD0   |PB0   |PA0   |PA1   |
|PD0   |PB0   |PA2   |PA3   |
|PD0   |PB1   |PA0   |PA1   |
|PD0   |PB1   |PA2   |PA3   |
|PD0   |PB2   |PA0   |PA1   |
|PD0   |PB2   |PA2   |PA3   |
|PD0   |PB3   |PA0   |PA1   |
|PD0   |PB3   |PA2   |PA3   |
|PD1   |PB0   |PA0   |PA1   |
|PD1   |PB0   |PA2   |PA3   |
|PD1   |PB1   |PA0   |PA1   |
|PD1   |PB1   |PA2   |PA3   |
|PD1   |PB2   |PA0   |PA1   |
|PD1   |PB2   |PA2   |PA3   |
|PD1   |PB3   |PA0   |PA1   |
|PD1   |PB3   |PA2   |PA3   |
+------+------+------+------+
Mapping as a relation value
---------------------------

所有这一切都是不值得的,并有意在一个好玩的精神。除非,也就是说,您需要进一步操作结果。然后关系运算符可以进行一些有趣的转换。

最新更新