2

I have a list as the following:

set list1 {1,2,3,4,5,6,7,8,9}

how to copy three elements of it to another list every time?

for example after copy:

listc1 is {1,2,3}
listc2 is {4,5,6}
listc3 is {7,8,9}
user2131316
  • 3,111
  • 12
  • 39
  • 53

3 Answers3

5

Your first statement is slightly off: Tcl does not use comma to separate list elements, it uses spaces. Below is a code snippet which will do what you want:

set list1 {1 2 3 4 5 6 7 8 9}
set counter 0
foreach {a b c} $list1 {
    set listc[incr counter] [list $a $b $c]
}

Discussion

  • The foreach statement takes 3 elements from the list at a time. In the first iteration, a=1, b=2, c=3. In the second, a=4, b=5, c=6 and so on.
  • The expression listc[incr counter] will yield listc1, listc2, ...
  • If the list's length is not divisible by three, then the last listc* will be filled with empty elements.
Hai Vu
  • 37,849
  • 11
  • 66
  • 93
  • do we have any build-in functions can specify the length of elements wanted to copy? – user2131316 Oct 02 '13 at 14:09
  • @user2131316, `lrange` extracts a contiguous sublist given the indices of its first and last elements in the source list. Each of these indices cound be derived from another (or from any arbitrary integer) using the `expr` command. Did you open [the tutorial](http://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html)? – kostix Oct 02 '13 at 14:32
  • @user2131316, see Glenn's solution. – Hai Vu Oct 02 '13 at 16:03
1

Here's one method, should work in any version of Tcl

proc partition {lst size} {
    set partitions [list]
    while {[llength $lst] != 0} {
        lappend partitions [lrange $lst 0 [expr {$size - 1}]]
        set lst [lrange $lst $size end]
    }
    return $partitions
}

set list1 {1 2 3 4 5 6 7 8 9}
lassign [partition $list1 3] listc1 listc2 listc3

foreach var {listc1 listc2 listc3} {puts $var=[set $var]}
listc1=1 2 3
listc2=4 5 6
listc3=7 8 9

In Tcl 8.6, I'd look into using a coroutine and yield the next partition.


Generalizing @kostik's answer:

proc partition {list size} {
    for {set i 0; set j [expr {$size - 1}]} {$i < [llength $list]} {incr i $size; incr j $size} {
        lappend partitions [lrange $list $i $j]
    }
    return $partitions
}
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1
set list1 {1 2 3 4 5 6 7 8 9}
set listc1 [lrange $list1 0 2]
set listc2 [lrange $list1 3 5]
set listc3 [lrange $list1 6 9]

Since Tcl 8.4 the last statement might be written as

set listc3 [lrange $list1 6 end]
kostix
  • 51,517
  • 14
  • 93
  • 176