Recursive Lists in Tcl

Hi,
I am new to tcl programming, i want to know how to write a procedure for list operations taking the user input from command line and outputs the the index of each element in the list.

Eg:
input list is : { 1 2 {ab cde} {acf t12 l34} 3 5{43 {try 5 }} } something like this.

output should help to get index as 20 for ab and 210 for element cde...etc
Is this an example for recursion??

Regards,
Leo

Some thing like this will work as long as nested lists have more than one members.

set a {a b {c {d e}}}
proc list_eval {list_name {prefix {}}} {
set end_point [expr [llength $list_name] -1]
    for {set start_point 0} {$start_point <= $end_point} {incr start_point} {
        if {[llength [lindex $list_name $start_point]] == 1} {
            puts "Index for [lindex $list_name $start_point] is $prefix$start_point"
        } else {
            append prefix $start_point
            list_eval [lindex $list_name $start_point] $prefix
        }        
}    
}    
list_eval $a

Output will be :
Index for a is 0
Index for b is 1
Index for c is 20
Index for d is 210
Index for e is 211

---------- Post updated 06-13-11 at 09:47 AM ---------- Previous update was 06-12-11 at 04:11 PM ----------

My pvs posted code was not correct, it will not work if last members of a main list is not a part of nested list. You can use modified code.

set a {a b {c {d e} h} i}
set glob_var {}
proc list_eval {list_name {prefix {}}} {
    global glob_var
set end_point [expr [llength $list_name] -1]
    for {set start_point 0} {$start_point <= $end_point} {incr start_point} {
        if {[llength [lindex $list_name $start_point]] == 1} {
            puts "Index for [lindex $list_name $start_point] is $prefix$start_point"
           if {$start_point == $end_point} {
           set glob_var [string range $glob_var 0 end-1]
            }
        } else {
            append glob_var $start_point
            list_eval [lindex $list_name $start_point] $glob_var
       }        
}    
}    
list_eval $a

Output:
Index for a is 0
Index for b is 1
Index for c is 20
Index for d is 210
Index for e is 211
Index for h is 22
Index for i is 3

1 Like

Hi,
Thanks for the help, it works fine.

---------- Post updated 06-14-11 at 01:12 PM ---------- Previous update was 06-13-11 at 03:38 PM ----------

Hi,

If to same input list i use linsert to insert a new element, how do i modify the present program such the the index update is also taken care of for newly added element and also rest of the elements.

Thanks,
Leo

You need to execute the procedure again in order to calculate the index of newly created list.

For instance if my initial list list1 has elements as 'a b c' and i inserted an element at last i need to pass this modified list again to procedure.

Are you saying you want to handle lindex based on index returned by procedure? like for "h" it is 22, so if you add new element it should add in nested list.

Can you pls elaborate on your requirement.

Let me put this way,
As in eg :
My original list: {a b {c {d e}}}
with indexes
a = 0
b = 1
c = 20
d = 210 etc

I ask user as :
puts "Enter new element"
gets stdin newel
puts "Enter index of new element"
gets stdin newind

So, if user gives newel as 1 and index as 2 my new list should be : { a b 2 {c {d e}}}
and correspondingly new indices should be
a = 0
b = 1
2 = 2
c = 30 etc...
and if user enters and index improper say in this eg user enters newind as 510 it should display error.

So how can take care of these in the earlier tcl script.

Thanks

Hi,

I tried the code as this:

set a "a cd {{{{lm st rm} {0 1} 2}} {1 0}} 5 6 7 8 {} ab"
set glob_var {}
proc list_eval {list_name {prefix {}}} {
    global glob_var
set end_point [expr [llength $list_name] -1]
    for {set start_point 0} {$start_point <= $end_point} {incr start_point} {
        if {[llength [lindex $list_name $start_point]] == 1} {
            puts "Index for [lindex $list_name $start_point] is $prefix$start_point"
           if {$start_point == $end_point} {
           set glob_var [string range $glob_var 0 end-1]
            }
        } else {
            append glob_var $start_point
            list_eval [lindex $list_name $start_point] $glob_var
       }        
}    
}    
list_eval $a

In output i see

Index for {{lm st rm} {0 1} 2}  is 20.

How can i fix this ???

Thanks,
Leo

I did something like this to achieve this, you can refine this code further. Basic just here is if length of list is 1, then you need to check whether this has further some members or not.

set a "a cd {{{{lm st rm} {0 1} 2}} {1 0}} 5 6 7 8 {} ab"
set glob_var {}
proc list_eval {list_name {prefix {}}} {
    global glob_var
set end_point [expr [llength $list_name] -1]
    for {set start_point 0} {$start_point <= $end_point} {incr start_point} {
        if {[llength [lindex $list_name $start_point]] && ![regexp ^\{ [lindex $list_name $start_point]]} {
            puts "Index for [lindex $list_name $start_point] is $prefix$start_point"
           if {$start_point == $end_point} {
           set glob_var [string range $glob_var 0 end-1]
            }
        } elseif {[llength [lindex $list_name $start_point]] && [regexp ^\{ [lindex $list_name $start_point]]} {
            set new_string1 [string trimleft [lindex $list_name $start_point] \{ ]
            set new_string2 [string trimright $new_string1 \}]   
            append glob_var $start_point
            list_eval $new_string2     
        } else {
            append glob_var $start_point
            list_eval [lindex $list_name $start_point] $glob_var
       }        
}    
}    
list_eval $a