我有一个包含映射的列表,如下
# {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
---------------------------
所有这一切都是不值得的,并有意在一个好玩的精神。除非,也就是说,您需要进一步操作结果。然后关系运算符可以进行一些有趣的转换。