所有组合均按列顺序排列

时间:2016-01-25 22:47:42

标签: algorithm tcl combinations nested-loops

我有一个网格,我们可以将这些列表示为ABC,行可以表示为x,y,z类型。

可能有多个行都被归类为相同的类型。列不是这样。

不应将相同类型的行组合或混合使用。"并且所有组合需要按照ABC的顺序,而不是CBA或其他任何组合。这是我提出的一个例子。

我需要打印下表的每个组合(按列顺序):

     A    B    C
   --------------
x | 10   20   30
x | 11   21   31

y | 40   50   60
y | 41   51   61

z | 70   80   90

输出必须像这样(它不必输出模式,仅供参考):

(Pattern) (Result)
Ax Bx Cx  {10 20 30} {11 21 31} (notice no mix-combinations on same letter x)
Ax Bx Cy  {10 20 60} {10 20 61} {11 21 60} {11 21 61}
Ax Bx Cz  {10 20 90} {11 21 90}
Ax By Cx  {10 50 30} {10 51 30} {11 50 31} {11 51 31}
Ax By Cy  {10 50 60} {10 51 61} {11 50 60} {11 51 61}
Ax By Cz  {10 50 90} {10 51 90} {11 50 90} {11 51 90}
Ax Bz Cx  {10 80 30} {11 80 31} 
Ax Bz Cy  {10 80 60} {10 80 61} {11 80 60} {11 80 61}  
Ax Bz Cz  {10 80 90} {11 80 90}  


Ay Bx Cx  {40 20 30} {40 21 31} {41 20 30} {41 21 31} 
Ay Bx Cy  ... 
Ay Bx Cz  ... 
Ay By Cx  ... 
Ay By Cy  ... 
Ay By Cz  ... 
Ay Bz Cx  ... 
Ay Bz Cy  ... 
Ay Bz Cz  ... 

Az Bx Cx  ... 
Az Bx Cy  ... 
Az Bx Cz  ... 
Az By Cx  ... 
Az By Cy  ... 
Az By Cz  ... 
Az Bz Cx  ... 
Az Bz Cy  ... 
Az Bz Cz  {30 60 90}

我有一些Tcl代码我已经开始做这个但不是很好。它没有考虑相同x y或z的多行,但这是我到目前为止所得到的:

set dl {0 1 2}
set op {x y z}

set debug [open "debugloop.txt" "w"]
set i 0
set j 0
set k 0
set e 0
set r 0
set s 0
set g yes
while {$g} {
  puts $debug A[lindex $op $i][lindex $dl $e]B[lindex $op $j][lindex $dl $r]C[lindex $op $k][lindex $dl $s]
  incr s
  if {$s > 2} {
    puts $debug ""
    incr r
    set s 0
    if {$r > 2} {
      puts $debug ""
      incr e
      set r 0
      if {$e > 2} {
        puts $debug ""
        incr k
        set e 0
        if {$k > 2} {
          puts $debug ""
          incr j
          set k 0
          if {$j > 2} {
            puts $debug ""
            incr i
            set j 0
            if {$i > 2} {
              set g no
            }
          }
        }
      }
    }
  }
}

有没有人比一系列硬编码嵌套循环有更好的方法呢?我对这个

有很多麻烦

1 个答案:

答案 0 :(得分:1)

您的问题有两个主要部分:

  1. 生成所有(模式)组合
  2. 以允许您查找每个组合的(结果)的方式存储数据。
  3. 对于第一个,您需要生成所有排列,并允许重复允许您的模式值x,y,z,在您的示例中。在tcl wiki上有一些代码。

    在您的情况下,顺序很重要,{x,y,z}与{z,y,x}不同,因此算法需要考虑到这一点。下面是一些使用简单算法生成重复排列的代码,它使用的理念是,您可以通过以模数为单位数来计算所有排列。排列的数量增长得非常快,请查看计算permCount的方式!

    # Permutaions
    proc NextPerm {perm values} {
    
        set result {}
        set needIncr 1
        foreach val $perm {
            if { $needIncr == 1} {
                set newVal [lindex $values [expr {[lsearch -exact $values $val] + 1}]]
                if {$newVal != ""} {
                    # New value was found
                    lappend result $newVal
                    set needIncr 0
                } else {
                    # No next value found so we need to carry
                    lappend result [lindex $values 0]
                }
            } else {
                lappend result $val
            }
        }
    
        return $result
    } 
    
    set values {x y z}
    set perm {x x x}
    
    puts $perm
    set  permCount [expr {[llength $perm] ** [llength $perm]}]
    for {set i 1} {$i < $permCount} {incr i} {
        set perm [NextPerm $perm $values]
        puts $perm
    }
    

    注意:我没有尝试优化此代码。

    如果模式值永远不会改变,而不是自己生成它们,你可以使用像this这样的在线资源(如果你进行搜索,还有很多其他网站)来生成值并将它们硬编码到你的计划。

    对于2,我会考虑将值存储在数组或dict中,并使用一个允许您拉回相关值的键。