所有组合按列顺序
All combinations in columnal order
我有一个网格,其中列可以表示为 ABC,行可以表示为 x、y、z 类型。
可能有多行都归类为同一类型。列不是这样。
不应合并相同类型的行,或者 "mixed." 所有合并都需要按照 ABC 的顺序,而不是 CBA 或其他任何顺序。这是我想出的一个例子。
我需要打印出以下每个组合(按列顺序排列)table:
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
}
}
}
}
}
}
}
有没有人有比一系列硬编码嵌套循环更好的方法来做到这一点?我遇到了很多麻烦
您的问题有两个主要部分:
- 正在生成所有(模式)组合
- 以允许您查找每个组合的(结果)的方式存储数据。
对于其中的第一个,您需要生成所有允许重复的排列,您的示例中的模式值 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 这样的在线资源(如果您进行搜索,还有很多其他网站)来生成值,而不是自己生成它们,并且 hard-code 他们进入你的程序。
对于 2,我会考虑将值存储在一个数组或一个字典中,并使用一个键让您可以提取相关值。
我有一个网格,其中列可以表示为 ABC,行可以表示为 x、y、z 类型。
可能有多行都归类为同一类型。列不是这样。
不应合并相同类型的行,或者 "mixed." 所有合并都需要按照 ABC 的顺序,而不是 CBA 或其他任何顺序。这是我想出的一个例子。
我需要打印出以下每个组合(按列顺序排列)table:
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
}
}
}
}
}
}
}
有没有人有比一系列硬编码嵌套循环更好的方法来做到这一点?我遇到了很多麻烦
您的问题有两个主要部分:
- 正在生成所有(模式)组合
- 以允许您查找每个组合的(结果)的方式存储数据。
对于其中的第一个,您需要生成所有允许重复的排列,您的示例中的模式值 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 这样的在线资源(如果您进行搜索,还有很多其他网站)来生成值,而不是自己生成它们,并且 hard-code 他们进入你的程序。
对于 2,我会考虑将值存储在一个数组或一个字典中,并使用一个键让您可以提取相关值。