我试图获得列表的最大值,列表可能包含零,0。在Tcl 8.5中,当我运行时:
set x {-5 -4 -3 -2 -1 0 1 2 3 4 5}
set maxx [expr max($x)]
set minx [expr min($x)]
puts "$minx $maxx"
我收到错误:
missing operator at _@_
in expression "max(-5 -4 -3 -2 -1 _@_0 1 2 3 4 5)"
(parsing expression "max(-5 -4 -3 -2 -1 0 1...")
invoked from within
"expr "max($x)""
invoked from within
"set maxx [expr "max($x"]"
我尝试过语法变异和我能找到的资源。
作为一种解决方法,我将使用lsort并获取该列表的第一个/最后一个元素,但我真的想知道我在这里做错了什么:/谢谢。
答案 0 :(得分:4)
Tcl表达式有点不同,你不能直接将列表填入其中并期望它能够正常工作。
我建议您直接使用::tcl::mathfunc::max
,使用参数展开({*}
):
set maxx [::tcl::mathfunc::max {*}$x]
set minx [::tcl::mathfunc::min {*}$x]
但如果您仍想使用expr
,可以尝试使用join创建有效的表达式:
set maxx [expr "max([join $x ,])"]
set minx [expr "min([join $x ,])"]
但是这个性能很差并且可以被利用(代码注入),考虑x
的这个输入:{-1 {[puts "Not good"; exit]} 2}
答案 1 :(得分:2)
一点阐述。如果它不合适,请告诉我。
对于解释器,调用foo {{a a a} {b b} c}
只有一个参数(由三个项或单词组成),foo {a a a} {b b} c
有三个参数(每个参数由三个,两个或一个项或单词组成)。只要命令的调用是正确的列表,解释器就不关心参数组成的内容或者它们的数量。命令otoh通常关心参数的数量和内容。
这意味着我们可能不得不偷偷摸摸。我们可以将foo
和bar
分配给变量x
吗?是的,但不是set x foo bar
,因为set
命令(不是解释器)需要一个或两个参数(变量名称和零或一个值)。如果我们将其作为set x {foo bar}
或set x [list foo bar]
调用,我们会得到正确数量的参数。
在其他时候,我们在列表中打包了一堆值,但是命令要求每个值都在它自己的参数中(您的max
命令就是一个例子)。 ::tcl::mathfunc::max {2 3 1}
失败,因为命令识别出它已被赋予单个值,并且该值应符合双精度浮点数的格式。在这种情况下,我们对列表中的值进行近似反演:我们将列表解压缩为参数。对于翻译来说,::tcl::mathfunc::max {*}{2 3 1}
与编写::tcl::mathfunc::max 2 3 1
一样有效。
(如果foo
是零个或一个项目的列表,set x {*}$foo
将始终有效。请考虑一下。)
将max
命令作为expr
表达式中的函数调用是另一种蠕虫。一般来说,使用expr
更简单,固定的表达式(例如expr {max($a,$b)}
)并找到f.i.(imho)会更好。通过调用命令而不涉及expr
来获取列表的最大值。