2015-08-17

Ordered numeric sequences

I wrote an answer on Stackoverflow, but I think the question is going to go away soon, so I'll post an edited version of my answer here.

The question was about how to find out whether digits in a sequence were in ascending (increasing) order or in descending (decreasing order). The sequence 1 2 3 is in increasing order, and so is 11 5, but this order is non-strict, i.e. the same digit may appear more than once if there are no other digits in between.

One can use mathematical comparison operators to check whether sequences of digits are in order:

foreach n {12345 54321 35214} {
    set ns [split $n {}]
    if {[::tcl::mathop::<= {*}$ns]} {
        puts "$n is in ascending order"
    } elseif {[::tcl::mathop::>= {*}$ns]} {
        puts "$n is in descending order"
    } else {
        puts "$n is neither in ascending or descending order"
    }
}

The command ::tcl::mathop::<= (which also implements the <= operator in expr) can take an arbitrary number of values, preferably numeric, and returns 1 if those values are in non-strict ascending order. It can be called directly on some values:

::tcl::mathop::<= 1 2 3 4 5
# -> 1

If the values are in a list it needs to be expanded first:

set a {1 2 3 4 5}
# -> 1 2 3 4 5
::tcl::mathop::<= {*}$a
# -> 1

If the values are packed in a string it needs to be split into a list and then expanded:

set a 12345
# -> 12345
::tcl::mathop::<= {*}[split $a {}]
# -> 1

The call to <= can be made a little less cumbersome by adding its namespace to the places where the interpreter looks for commands:

namespace path ::tcl::mathop
<= 1 2 3 4 5

Documentation: foreachiflistmathopnamespaceputssetsplit{*}

2 comments:

  1. Line 5 should be [::tcl::mathop::>= {*}$ns] :P

    ReplyDelete
  2. Oops yes. An error in transcription from SO. Thank you.

    ReplyDelete