Tcl 循环遍历所有阵列组合(可变大小)

Tcl 循环遍历所有阵列组合(可变大小),tcl,combinations,permutation,Tcl,Combinations,Permutation,在tcl中,我需要为未知数量的变量值的每个可能组合执行一个脚本 用文字描述: A从a0->a1开始,步数为“da” B从b0->b1开始,步骤为“db” C从c0->c1开始,步数为“dc” 变量的数量可能会有所不同。注意:变量的名称事先不知道,“A”也可以称为“Ape”或其他任何名称。其他变量也是如此 到目前为止,我得到的是: array set min_vals {A $a0 B $b0 C $c0 ...} ;# --> These are user-defined array s

在tcl中,我需要为未知数量的变量值的每个可能组合执行一个脚本

用文字描述:

A从a0->a1开始,步数为“da”

B从b0->b1开始,步骤为“db”

C从c0->c1开始,步数为“dc”

变量的数量可能会有所不同。注意:变量的名称事先不知道,“A”也可以称为“Ape”或其他任何名称。其他变量也是如此

到目前为止,我得到的是:

array set min_vals {A $a0 B $b0 C $c0 ...} ;# --> These are user-defined
array set max_vals {A $a1 B $b1 C $c1 ...} ;# --> These are user-defined
array set step_vals {A $da B $db C $dc ...} ;# --> These are user-defined

# First I determine the number of variables and the number of values they can have
set nr_vars [array size min_vals] ;# Determine nr of variables
set nr_vals [list] ;# --> Set empty list for nr of values for each variable

foreach var_name [array names min_vals] {
    set nr [expr {round( ( $max_vals(${var_name})-$min_vals(${var_name}) ) / $step_vals(${var_names}) )}]
    set nr_vals [concat $nr_vals $nr]
}
现在,我需要以某种方式循环每个可能的组合:

[A=a0, B=b0, C=c0]
[A=a0+da, B=b0, C=c0]
[A=a0+2*da, B=b0, C=c0]
...
...
[A=a1, B=b0, C=c0]
[A=a0, B=b0+db, C=c0]
[A=a0+da, B=b0+db, C=c0]
...
...
[A=a1, B=b1, C=c1]
我希望有一个简单的方法来做到这一点。我能想到的唯一方法是使用包含所有组合的迭代次数的单个循环,并让每个迭代次数对应于特定的组合。但我相信一定有一种不那么麻烦的方法

_

编辑:

也许我不太清楚我到底想要什么。我不在乎实际产出。我的目标是将每个变量设置为正确的值,并使用这些变量运行另一个脚本:

set A $a0
set B $b0
set C $c0
source run/some/script.tcl
并对
A
B
C
的值的每个可能组合重复此操作,使用嵌套for循环

for {set a $min_vals(A)} {$a <= $max_vals(A)} {incr a $step_vals(A)} {
    for {set b $min_vals(B)} {$b <= $max_vals(B)} {incr b $step_vals(B)} {
        for {set c $min_vals(C)} {$c <= $max_vals(C)} {incr c $step_vals(C)} {

            do something with [list $a $b $c]

        }
    }
}

用于{set a$min_vals(a)}{$a可以帮助您获得一些想法。谢谢glenn,这似乎将我推向了正确的方向。我知道我需要一个嵌套循环,但我不确定如何实现。但是如果我阅读了您的脚本,请首先确定需要的循环数,然后将其放入字符串
$code
,然后按如下方式执行
$code
如果它是一个单独的脚本,
%s
$:max\u vals
做什么?第16行中的'123\n'是什么?我更新了代码,使之更简单。
%s
是(
格式
是Tcl的
sprintf
)这是一个很好的方法。但是我必须修改一些东西,使其按照我想要的方式工作。我需要使用非整数,因此我用
替换
for
,而
并使用
set[expr{$%s+[lindex$step\u vals%s]}在循环中添加增量
。我还将初始输入值更改为lists
设置最小值{1 10 10}
set variables {A B C}
array set min_vals  {A 1 B 10 C 100}
array set max_vals  {A 3 B 30 C 300}
array set step_vals {A 1 B 10 C 100}

proc build_loops {} {
    global variables 

    # create the "seed" code: what to do with the generated tuple
    set code "do_something_with \[list "
    foreach var $variables { 
        append code "\$[loop_var $var] " 
    }
    append code "]"

    # and wrap layers of for loops around the seed
    foreach var [lreverse $variables] {
        set loop_var [loop_var $var]
        set code [format {for {set %s $min_vals(%s)} {$%s <= $max_vals(%s)} {incr %s $step_vals(%s)} {%s}} \
            $loop_var $var \
            $loop_var $var \
            $loop_var $var \
            $code \
        ]
    }

    return $code
}

proc loop_var {varname} {
    return "loop_[string tolower $varname]"
}

proc do_something_with {args} {
    puts $args
}

set code [build_loops]
puts $code
eval $code
for {set loop_a $min_vals(A)} {$loop_a <= $max_vals(A)} {incr loop_a $step_vals(A)} {for {set loop_b $min_vals(B)} {$loop_b <= $max_vals(B)} {incr loop_b $step_vals(B)} {for {set loop_c $min_vals(C)} {$loop_c <= $max_vals(C)} {incr loop_c $step_vals(C)} {do_something_with [list $loop_a $loop_b $loop_c ]}}}
{1 10 100}
{1 10 200}
{1 10 300}
{1 20 100}
{1 20 200}
{1 20 300}
{1 30 100}
{1 30 200}
{1 30 300}
{2 10 100}
{2 10 200}
{2 10 300}
{2 20 100}
{2 20 200}
{2 20 300}
{2 30 100}
{2 30 200}
{2 30 300}
{3 10 100}
{3 10 200}
{3 10 300}
{3 20 100}
{3 20 200}
{3 20 300}
{3 30 100}
{3 30 200}
{3 30 300}