1
votes

i am new to tcl , i am trying to get the max element in a given list i wrote a function that prints the max but it is not working properly here is the code

proc findmax { items } {
  set max 1
  foreach i $items { 
    if { $i > $max } {
      set $max $i
    }
  }
  puts "max is = $max"
}

and i called the function like this :

findmax $items

this is the list i passed :

set items { 12 2 5 4 2 6 7 55 8 9 6 4}

but it outputs 1 and not 55 as expected

1
set $max $i -- What is the first argument to the set command, a variable name or a variable value?glenn jackman
Also, a safer way to set the initial value for max is to use the first element of the list: consider the case where all the list elements are negative: set max [lindex $items 0]glenn jackman
about setting the max as the first element in the list i totally agree. thank you so much ! i found where i was wrongLight Yagami
set max $i instead of set $max $i !!! you pointed me to the problemLight Yagami
Finding the maximum value of a list is a one-liner in Tcl anyway: set max [tcl::mathfunc::max {*}$items]Donal Fellows

1 Answers

4
votes

Your problem is this line:

set $max $i

In Tcl, the $ character means read from the named variable and use that value as (possibly part of) the argument to a command. It means this always. No exceptions (unless backslash-quoted or in {braces}, of course). Thus, on the first iteration of the loop you're getting (after substitution):

set 1 12

The variable name 1 is legal, but unusual and not what you want. For the algorithm to work, you instead want to give the set command the name of the variable to set, max, resulting in this:

set max $i

which will be substituted to this on the first iteration:

set max 12

That looks right! A good rule of thumb for future programming is that if a command manipulates a variable (setting it or updating it) then you need to pass the name of the variable, not the value retrieved from it.


The standard method of getting the maximum value of a list is a one-liner:

set max [tcl::mathfunc::max {*}$items]

This uses the built-in function max (which is in the ::tcl::mathfunc namespace) and passes the contents of the list in items as multiple arguments, all as one step. The {*}$ sequence is a combination of the variable-read syntax rule with the list-expansion rule, which you've probably not really thought about yet. However it's still a good exercise to write your own maximum finder as a learning exercise.