I'm a beginner in tcl and here's my question (same as title!):
how can I retrieve the index of the minimum value of a list?
I already have the min value (and the max value) by using
::math::statistics::min & ::max, and I need now the index.
In fact, I want to change the foreground of the min value and the max
value of 13 lists.
If anybody can help me...
thanks in advance,
alexis
proc minindex list {
set index 0
set minindex $index
set minval [lindex $list 0]
foreach val $list {
if {$val < $minval} {
set minindex $index
set minval $val
}
incr index
}
return $minindex
}
653 % minindex {3 2 1 11 12 0 345}
5
> I already have the min value (and the max value) by using
> ::math::statistics::min & ::max, and I need now the index.
> In fact, I want to change the foreground of the min value and the max
> value of 13 lists.
If you already have the min/max value of a list, you can use lsearch:
| % set myList {2 8 6 0 45 7 9}
| 2 8 6 0 45 7 9
| % set min 0
| 0
| % set max 45
| 45
| % lsearch $myList $min
| 3
| % lsearch $myList $max
| 4
| %
Regards
Stephan
# fill a random list
for { set idx 0 } { $idx < 100 } { incr idx } {
# you may want to add other information into these lists
# like widgetname, colorvalue whatnot
lappend numlist [ expr { int(rand() * 100) } ]
}
set idx 0
foreach item $numlist {
lappend ::complex [ list $item $idx ]
incr idx
}
# sort the list on element 0 of every item
set ::sorted [ lsort -integer -index 0 $::complex ]
set minitem [ lindex $::sorted 0 ]
foreach { minval minidx } $minitem break
set maxitem [ lindex $::sorted end ]
foreach { maxval maxidx } $maxitem break
puts [ format "max:% 4d @ % 4d" $maxval $maxidx ]
puts [ format "min:% 4d @ % 4d" $minval $minidx ]
uwe
# fill a random list
for { set idx 0 } { $idx < 100 } { incr idx } {
Assuming the lists are unsorted, finding the (first) location of a known
value in a list is simply a matter of using the [lsearch] command:
set index [lsearch -exact $theList $value]
If you want all the places in the list where it occurs (after all, in a
general list it might be in two or more spots) add the -all option to
get a list of indices:
set allIndices [lsearch -exact -all $theList $value]
Once you've got all the indices, use [foreach] to go over them all and
process them...
Donal.
But now, it's another kind of problem.
As I said, I want to configure the foreground of several item in
several lists.
My problem is that I have 13 lists (called state(xxxx) ) and I don't
want to do it separatly.
I have try this:
foreach { name value } [array get state] {
set min($name) [::math::statistics::min $state($name)]
set max($name) [::math::statistics::max $state($name)]
for {set list_nb 1} {$list_nb <= 13} {incr list_nb} {
set minindex($name) [lsearch $state($name) $min($name)]
set maxindex($name) [lsearch $state($name) $max($name)]
Listbox$list_nb itemconfigure $minindex($name) -foreground
green
Listbox$list_nb itemconfigure $maxindex($name) -foreground red
}
}
but it don't works because of that: $state($name) (of course also this
$maxindex($name) , etc)
I don't know how to do it.
If someone have the answer, it will be great!
Thanks in advance.
alexis
I see a couple of problems. First you are storing information in two
locations
the state array and the listbox which means that you will need to do
extra work
to keep them synchronized. Next there seems to be no correspondance
between
your listboxes and your state array. You imply a correspondance because
you never
search the listboxes for the minimum and maximum which you should if
there is no
correspondance. Thus you are setting the background color on all
listboxes for the minimum found in state(1) ( assuming for the second
your array indexes are integers). So the index for the minium of
state(1) is 5. Listbox 1 has the value 8 at index 5, Listbox2 has the
value 32 at index 5 .... You can see that you are setting background
colors for items that do
not correspond to the minium on at least 12 of the listboxes. Also
inside the loop around the
listboxes you set the minindex($name) and maxindex($name) 13 times when
one time would be
sufficent as the code for setting these variables does not depend on
the loop counter or any local variable to the loop.
I assume this is similar to your setup
array set state { 0 { 1 3 4 5 6 7 }
1 { 1 3 5 7 9 32 }
2 { 2 4 6 8 }
...
12 { 1 2 3 4 5 }
}
# state(0) corresponds to listbox0 etc
foreach { name listvalue } [ array get state ] {
set min [::math::statistics::min $listvalue ]
set max [::math::statistics::max $listvalue]
#for the corresponding listbox determine the index of the minimum
if { [ llength [ eval listbox \$Listbox$name get 0 ] ] == 0 } {
continue; # nothing to do no items }
set minindex [ lsearch -exact [ eval listbox \$Listbox$name get 0
] $min ]
set maxindex [lsearch -exact [ eval listbox \$Listbox$name get 0 ]
$max ]
if { $maxindex != -1 } {
eval listbox \$Listbox$name itemconfigure $maxindex
-foreground red
}
if { $minindex != -1 } {
eval listbox \$Listbox$name itemconfigure $minindex
-foreground green
}
if { $minindex != -1 && $maxindex != -1 && $maxindex == $minindex
} {
# case of list of one where min = max
eval listbox \$Listbox$name itemconfigure $minindex
-foreground purple
}
}
If you really want to highlight the minumum and maximum for every state
list in every listbox
you need to add the loop. Though you will likely end up with a patch
work of colors on all your
list boxes. depending on your data.
foreach { name listvalue } [ array get state ] {
set min [::math::statistics::min $listvalue ]
set max [::math::statistics::max $listvalue]
#for the corresponding listbox determine the index of the minimum
for { set n 0 } { $n < 13 } { incr n } {
if { [ llength [ eval listbox \$Listbox$n get 0 ] ] == 0 }
{ continue; # nothing to do no items }
set minindex [ lsearch -exact [ eval listbox \$Listbox$n
get 0 ] $min ]
set maxindex [lsearch -exact [ eval listbox \$Listbox$n
get 0 ] $max ]
if { $maxindex != -1 } {
eval listbox \$Listbox$n itemconfigure $maxindex
-foreground red
}
if { $minindex != -1 } {
eval listbox \$Listbox$n itemconfigure $minindex
-foreground green
}
if { $minindex != -1 && $maxindex != -1 && $maxindex ==
$minindex } {
# case of list of one where min = max
eval listbox \$Listbox$n itemconfigure $minindex
-foreground purple
}
}
}
BTW I did not test this code so there may be gramatical errors.