{{ht a3 pr2} {ht a2 pr1} {lt a1 pr2} {lt a3 pr4} {ht a2 pr2}}
into a list like this one:
{{ht ht ht lt lt} {a2 a2 a1 a3} {pr1 pr2 pr2 pr2 pr4}}
so that to rotate the columns to rows and retain original
correspondence between the list elements.
can someone please help me figure out the trick?
-a.
Sorry, I did not get what you mean. Could you write it with indexes ?
{
{0 1 2}
{0 1 3}
{0 2 1}
{1 1 2}
{1 2 3}
}
converted to :
{
{0 0 0 1 1}
{1 1 2 1 2}
{2 3 1 2 3}
}
# initial code
proc rotate_list { list } {
set lWidth [llength $list]
set lHeight [llength [lindex $list 0]]
set w $lHeight
set h $lWidth
set list {}
for {set i 0} {$i < h} {incr i} {
for {set j 0} {$j < w} {incr j} {
list [i][j] = list[w - j -1] [i]
}
}
return list
}
what I am stuck at is this line:
list [i][j] = list[w - j -1] [i]
thanks!
-a.
I modified the code a bit:
# code
proc rotate_list { list } {
set lWidth [llength $list]
set lHeight [llength [lindex $list 0]]
set w $lHeight
set h $lWidth
set lst {}
for {set i 0} {$i < $h} {incr i} {
set case {}
for {set j 0} {$j < $w} {incr j} {
#list [i][j] = list[w - j -1] [i]
#lappend lst [expr {$w - $j -1} * $i]
lappend case [expr {$w - $j -1} * $i]
}
lappend lst $case
}
set lst
}
it does the rotation but i can't figure out why it returns indices
instead of letters now.
% set m {{ht a2 pr2} {ht a2 pr1} {lt a1 pr2} {ht a3 pr2} {lt a3 pr4}}
{ht a2 pvt2} {ht a2 pvt1} {lt a1 pvt2} {ht a3 pvt2} {lt a3 pvt4}
% rotate_list $m
{3 2 1} {2 1 0} {1 0 -1} {0 -1 -2} {-1 -2 -3}
can someone please help with this?
#!/usr/bin/tclsh
proc prettyprintlist list {
puts \{
foreach line $list {
puts -nonewline \t\{\
foreach item $line {
puts -nonewline [ format %10s $item ]
}
puts \t\}\
}
puts \}
}
proc listrot list {
set columns {}
set col 0
foreach line $list {
if {!$col} {
foreach item $line {
lappend columns c:$col
incr col
}
}
set col 0
foreach item $line {
lappend c(c:$col) $item
incr col
}
}
foreach tok $columns {
lappend ret $c($tok)
}
return $ret
}
set ilist {
{0 1 2}
{0 1 3}
{0 2 1}
{1 1 2}
{1 2 3}
}
prettyprintlist $ilist
set olist [ listrot $ilist ]
prettyprintlist $olist
#end
Hi,
here a version of prettyprintlist that works.
Hi,
this looks like you want to transpose a matrix. You could use
struct::matrix from tcllib. It already provides this functionality.
http://tcllib.sourceforge.net/doc/matrix.html
Rüdiger
thanks, Rüdiger! that helped. i wrote my own implementation for
transposing the list based on what they had there. thanks!
uwe
#!/usr/bin/tclsh
set ilist {
{0 1 2}
{0 1 3}
{0 2 1}
{1 1 2}
{1 2 3}
}
# assume size of each row to be same
set num_col [llength [lindex $ilist 0]]
set i 0
set nlist {}
foreach r $ilist {
puts "$i -> $r"
set j 0
foreach c $r {
if {$i == 0} {
lappend nlist [list $c]
} else {
set l [lindex $nlist $j]
lappend l $c
lset nlist $j $l
}
incr j
}
incr i
}
puts "\ntransposed list --->"
set i 0
foreach ele $nlist {
puts "$i -> $ele"
incr i
}
For the case given you could do the following (assuming the first list
is in a variable named alist).
foreach a b c d e {*}${alist} {
lappend result [list $a $b $c $d $e]
}
The result isn't exactly the same result suggested because it appears
the elements is the suggested result appear to have been sorted while
my example is a rotation.
tomk
OOPS,
The above code doesn't work. This is what it should have been.
set alist [list {ht a3 pr2} {ht a2 pr1} {lt a1 pr2} {lt a3 pr4} {ht a2
pr2}]
set i 0
foreach a ${alist} {
lappend args a${i} ${a}
incr i
}
set res ""
foreach {a b} ${args} {
append res " \$${a}"
}
foreach {*}${args} {
lappend result [eval list $res]
}
puts $result
And you will get the following.
{ht ht lt lt ht} {a3 a2 a1 a3 a2} {pr2 pr1 pr2 pr4 pr2}
Regards,
tomk
Your version had a trailing \ with some puts that did not work for me.
For example
Compare 'puts -nonewline \t\{\'
with 'puts -nonewline \t\{'
That is the change.
Rüdiger
what I posted was 'puts -nonewline \t\{\<space>'
"\t\{ " would have been equivalent for the payload
Not quite sure who had the <space> for dinner.
uwe
anyway, your suggestions used only half the time of struct::matrix.
also i wonder why my code is so much faster....
timing results:
tomk 2078.416 microseconds per iteration
ruchir 2002.312 microseconds per iteration
uwe 1921.835 microseconds per iteration
kob 1043.529 microseconds per iteration
::struct::matrix 4082.555 microseconds per iteration
for your convenience find the script used for testing bellow
cheers,
mark
p.s. feedback is appreciated
--- code follows ---
#!/usr/bin/tclsh
::puts "transpose \nUsage:"
::puts "transpose ?--time?"
::set mi 20
::set mj 50
::package require struct::matrix
::set clist {
{0 1 2 }
{0 1 3 }
{0 2 1 }
{1 1 2 }
{1 2 3 }
}
::struct::matrix mycmatrix
mycmatrix deserialize [::list 5 3 $clist]
## prepare the test data
::puts "init"
::proc getnum {} {
::return [::expr {100000*rand()}]
}
::struct::matrix mymatrix
::set mymatrixlist [::list]
::for {::set i 0 } {$i < $mi } {::incr i } {
::set row [::list]
::for {::set j 0 } {$j < $mj } {::incr j } {
::lappend row [getnum]
}
::lappend mymatrixlist $row
}
mymatrix deserialize [::list $mi $mj $mymatrixlist]
## procs
## tcllib
proc transpose { } {
mymatrix transpose
}
::proc tomk { alist } {
set i 0
foreach a ${alist} {
lappend args a${i} ${a}
incr i
}
set res ""
foreach {a b} ${args} {
append res " \$${a}"
}
foreach {*}${args} {
lappend result [eval list $res]
}
return $result
}
::proc ttranspose {} {
tomk $::mymatrixlist
}
## ashneerson
::proc rotate_list { list } {
::set W [::llength $list]
::set H [::llength [::lindex $list 0]]
::set w $H
::set h $W
::set lst [::list ]
::for {::set i 0 } {$i < $h} {incr i} {
::set case [::list ]
::for {::set j 0} {$j < $w} {incr j} {
::lappend case [::lindex $list [::expr {($w-$j
-1)}] $i]
}
::lappend lst $case
}
::return $lst
}
::proc arotate { } {
::rotate_list $::mymatrixlist
}
## uwe
::proc listrot list {
::set columns {}
::set col 0
::foreach line $list {
::if {!$col} {
::foreach item $line {
::lappend columns c::$col
::incr col
}
}
::set col 0
::foreach item $line {
::lappend c(c::$col) $item
::incr col
}
}
::foreach tok $columns {
::lappend ret $c($tok)
}
::return $ret
}
::proc utranspose {} {
listrot $::mymatrixlist
}
## kob
## taken from my matrix namespace
::proc dim { A } {
::set i [::llength $A ]
::set j [::llength [::lindex $A 0] ]
::return [::list $i $j ]
}
::proc Mat { dai x daj } {
::for {::set i 0} {$i<$daj } {::incr i} {
::lappend list 0
}
::for {::set i 0} {$i<$dai} {::incr i} {
::lappend C $list
}
::return $C
}
::proc T { A } {
::foreach [::list dai daj ] [dim $A] ::break
::set B [Mat $daj x $dai]
::set i 0
::foreach a $A {
::set j 0
::foreach aij $a {
::lset B $j $i $aij
::incr j
}
::incr i
}
::return $B
}
##
::proc ktranspose { } {
T $::mymatrixlist
}
## ruchir
::proc ruchir { A } {
::set i 0
::set nlist [::list ]
::foreach r $A {
::set j 0
::foreach c $r {
::if {$i == 0 } {
::lappend nlist [::list $c]
} else {
::set l [::lindex $nlist $j]
::lappend l $c
::lset nlist $j $l
}
::incr j
}
::incr i
}
::return $nlist
}
::proc rtranspose {} {
ruchir $::mymatrixlist
}
::if {[::lsearch $argv --time]>=0} {
## cache
::puts "prepare bytecode"
rtranspose
utranspose
ktranspose
ttranspose
transpose
## time
::puts "timing results:"
::puts -nonewline "tomk "
::puts [::time {
ttranspose
} 1000]
::puts -nonewline "ruchir "
::puts [::time {
rtranspose
} 1000]
::puts -nonewline "uwe "
::puts [::time {
utranspose
} 1000]
::puts -nonewline "kob "
::puts [::time {
ktranspose
} 1000]
::puts -nonewline "::struct::matrix "
::puts [::time {
transpose
} 1000]
}
::puts "correctness"
::puts -nonewline "solution: "
::puts [::list {0 0 0 1 1} {1 1 2 1 2} {2 3 1 2 3} ]
::puts -nonewline "tomk "
::puts [tomk $clist]
::puts -nonewline "ruchir "
::puts [ruchir $clist]
::puts -nonewline "uwe "
::puts [listrot $clist]
::puts -nonewline "kob "
::puts [T $clist]
::puts -nonewline "struct::matrix "
mycmatrix transpose
::puts [::lindex [mycmatrix serialize ] 2]
I wrote a proc for this, for some reason called it matrix:
proc ::resource::matrix { inList outList cols } {
# procedure creates new list from input list
# cols is the result set cols == input rows
# cols is an artificial dimension, which along
# with the length of the list determines the
# dims of the matrix. The list is filled
# with {} until the matrix is complete:
# 1 2 3 4 1 5 9
# 5 6 7 8 - cols = 3 -> 2 6 10
# 9 10 11 {} 3 7 11
# 4 8 {}
#
upvar $inList IL
upvar $outList OL
set rows [expr round(ceil([llength $IL].0/$cols))]
# make matrix
set Index [expr ($rows * $cols)]
set OL [list]
for {set i 0} {$i < $Index} {incr i} {
set x [expr $i/$cols ]
set y [expr $i % $cols]
# flip x y
lappend OL [lindex $IL [expr $y * $rows + $x] ]
}
}
Link to original source:
http://junom.com/gitweb/gitweb.perl?p=tnt.git;a=blob;f=packages/resource/tcl/resource-procs.tcl;h=45752;hb=HEAD#l100
Of course I assume you should agree that matrix dimensions are
imaginary projections of a simple list...but why choose a complex
structure and then try to manipulate it into a different form? This
choice could require a mapping for each matrix element.
Maybe I should clarify: in Tcl there is no way to identify the
dimensions of a matrix, in Tcl every matrix has one row and the number
of columns is equal to the number of list elements. If you think
otherwise you are bound to fail. In Tcl multi-dimensional arrays or
matrices are a construction of the program's interpretation of the
data. So basically you can't transpose a matrix in Tcl unless you
specify the matrix dimensions (you can't just point to the matrix).
Maybe tcllib's matrix command is the best option.