2023-12-06 08:29:33 +00:00
|
|
|
package require Tcl 8.6
|
|
|
|
namespace import tcl::mathfunc::min
|
|
|
|
namespace import tcl::mathfunc::max
|
|
|
|
|
2023-12-07 21:59:35 +00:00
|
|
|
proc {#} args {}
|
|
|
|
|
2023-12-19 04:49:17 +00:00
|
|
|
# short aliases for common things
|
|
|
|
|
2023-12-13 07:11:53 +00:00
|
|
|
proc llen {lst} { return [llength $lst] }
|
|
|
|
proc slen {str} { return [string length $str] }
|
|
|
|
proc trim args { return [uplevel [concat string trim $args]] }
|
|
|
|
proc replace {str a b} { return [string map [list $a $b] $str] }
|
|
|
|
|
2023-12-19 04:49:17 +00:00
|
|
|
# sum and product
|
|
|
|
|
2023-12-06 08:29:33 +00:00
|
|
|
proc ladd {list} {
|
|
|
|
set t 0
|
|
|
|
foreach x $list { incr t $x }
|
|
|
|
return $t
|
|
|
|
}
|
|
|
|
|
|
|
|
proc lmul {list} {
|
|
|
|
set p 1
|
2023-12-09 07:16:10 +00:00
|
|
|
foreach x $list { set p [expr {$p * $x}] }
|
2023-12-06 08:29:33 +00:00
|
|
|
return $p
|
|
|
|
}
|
|
|
|
|
2023-12-13 07:11:53 +00:00
|
|
|
# split s on a substring
|
|
|
|
proc splitstr {s sep} {
|
|
|
|
# replace $sep with ascii char 30, aka "record separator"
|
|
|
|
return [split [replace $s $sep "\x1E"] "\x1E"]
|
|
|
|
}
|
|
|
|
|
2023-12-08 02:35:27 +00:00
|
|
|
proc must_regexp args {
|
|
|
|
if {! [uplevel [concat regexp $args]]} {
|
|
|
|
error "regexp failed"
|
|
|
|
}
|
|
|
|
}
|
2023-12-14 09:00:36 +00:00
|
|
|
|
2023-12-19 04:49:17 +00:00
|
|
|
# transpose a list of strings
|
|
|
|
#
|
|
|
|
# % transpose {abc 123}
|
|
|
|
# a1 b2 c3
|
|
|
|
# % transpose a1 b2 c3
|
|
|
|
# abc 123
|
|
|
|
#
|
2023-12-14 09:00:36 +00:00
|
|
|
proc transpose strings {
|
|
|
|
set out {}
|
|
|
|
set C [slen [lindex $strings 0]]
|
|
|
|
for {set i 0} {$i < $C} {incr i} {
|
|
|
|
set column {}
|
|
|
|
foreach row $strings {
|
|
|
|
lappend column [string index $row $i]
|
|
|
|
}
|
|
|
|
lappend out [join $column ""]
|
|
|
|
}
|
|
|
|
return $out
|
|
|
|
}
|
2023-12-19 04:50:01 +00:00
|
|
|
|
2023-12-19 04:54:36 +00:00
|
|
|
# transpose a list of lists
|
|
|
|
#
|
|
|
|
# % ltranspose {{a b c} {1 2 3}}
|
|
|
|
# {a 1} {b 2} {c 3}
|
|
|
|
# % ltranspose {{a 1} {b 2} {c 3}}
|
|
|
|
# {a b c} {1 2 3}
|
|
|
|
#
|
|
|
|
proc ltranspose lists {
|
|
|
|
set out {}
|
|
|
|
set C [llen [lindex $lists 0]]
|
|
|
|
for {set i 0} {$i < $C} {incr i} {
|
|
|
|
set column {}
|
|
|
|
foreach row $lists {
|
|
|
|
lappend column [lindex $row $i]
|
|
|
|
}
|
|
|
|
lappend out $column
|
|
|
|
}
|
|
|
|
return $out
|
|
|
|
}
|
|
|
|
|
2023-12-19 04:50:01 +00:00
|
|
|
# extracts one or more indexes from a strided list
|
|
|
|
# e.g.
|
|
|
|
# % set l {0 1 2 a b c x y z}
|
|
|
|
# % lextract $l 3 0
|
|
|
|
# 0 a x
|
|
|
|
# % lextract $l 3 {1 2}
|
|
|
|
# 1 2 b c y z
|
|
|
|
#
|
|
|
|
# equivalent to [lmap {a b c} $lst {list $b $c}] except that
|
|
|
|
# you don't have to name the list elements
|
|
|
|
proc lextract {lst stride index} {
|
|
|
|
set i 0
|
|
|
|
set out {}
|
|
|
|
if {$stride <= 0} { error "stride must be positive: $stride" }
|
|
|
|
for {set i 0} {$i < [llength $lst]} {incr i $stride} {
|
|
|
|
foreach j $index {
|
|
|
|
lappend out [lindex $lst $i+$j]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $out
|
|
|
|
}
|