遍历所有数组组合(可变大小)

时间:2014-03-18 08:44:04

标签: 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 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

ABC的每种可能值组合重复此操作。

1 个答案:

答案 0 :(得分:0)

使用嵌套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 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}

我保留了一个单独的变量名列表:[array names a]返回一个无序名称列表,并且(我假设)知道给予该元组的元组的顺序很重要。 do_something_with proc