Append a string to variable during array creation - arrays

I'm attempting to create a very simple array in TCL but I can't figure out the syntax to make it append text to a variable in an assignment. Here is what I am trying to do:
set var1 "some text"
set var2 "other text"
array set arrValues {
1 $var1 + _text
2 $var2 + _text
3 $var1 + _different_text
4 $var1 + _different_text
}
How do I tell it that it should treat $var1 + _text as the data that needs to get inserted without needing to make another variable outside of the array?

Since you want to substitute the variables, you can't use {braces} to declare the array elements:
$ tclsh
% set var1 "some text"
some text
% set var2 "other text"
other text
% array set arrValues {1 ${var1}_text 2 ${var2}_text 3 ${var1}_different_text 4 ${var2}_different_text}
% parray arrValues
arrValues(1) = ${var1}_text
arrValues(2) = ${var2}_text
arrValues(3) = ${var1}_different_text
arrValues(4) = ${var2}_different_text
% array set arrValues [list 1 ${var1}_text 2 ${var2}_text 3 ${var1}_different_text 4 ${var2}_different_text]
% parray arrValues
arrValues(1) = some text_text
arrValues(2) = other text_text
arrValues(3) = some text_different_text
arrValues(4) = other text_different_text

You can just join the string together... But so it knows where the variable name ends, put it in braces ${var1}_text... And so your array values get evaluated, put them in quotes instead of braces, or use [list a b c]
(Please excuse lack of format - answering from my phone)

The simplest robust way is probably to use the list command to construct the thing to use with array set:
set var1 "some text"
set var2 "other text"
array set arrValues [list \
1 "$var1 + _text" \
2 "$var2 + _text" \
3 "$var1 + _different_text" \
4 "$var1 + _different_text"
]
That's assuming that you want just the variable substituted. ("${var1}_text" might be more suitable for your specific case; you can build the value to insert using any Tcl substitutions you want.) However, in this case I'd actually just do this instead:
set var1 "some text"
set var2 "other text"
set arrValues(1) "$var1 + _text"
set arrValues(2) "$var2 + _text"
set arrValues(3) "$var1 + _different_text"
set arrValues(4) "$var1 + _different_text"
It's shorter. The array set command only really becomes useful when you are using literal dictionaries as the source of what to set, or when you're taking a serialized value generated elsewhere entirely (e.g., from an array get in another context).

Related

How to dynamically create array and assign value in TCL

I want to create array dynamically and assign value to it. e.g.
set num 0
foreach i {1 2 3} {
set count$i(sp) {$num}
incr num
set count$i(ep) [expr $num+1]
}
When I ran your sample code, this error comes up:
can't read "i(sp)": variable isn't array
which is because the $i(sp) part of count$i(sp) looks like a reference to an existing array i.
You'll want to isolate $i from (sp) with curly brackets:
set num 0
foreach i {1 2 3} {
set count${i}(sp) {$num}
incr num
set count${i}(ep) [expr $num+1]
}
which creates three arrays:
tcl8.6.8> parray count1
count1(ep) = 2
count1(sp) = $num
tcl8.6.8> parray count2
count2(ep) = 3
count2(sp) = $num
tcl8.6.8> parray count3
count3(ep) = 4
count3(sp) = $num
Note above that curly brackets around $num use the literal string $num.
You'll want to remove those curly brackets:
set num 0
foreach i {1 2 3} {
set count${i}(sp) $num
incr num
set count${i}(ep) [expr $num+1]
}
tcl8.6.8> parray count1
count1(ep) = 2
count1(sp) = 0
tcl8.6.8> parray count2
count2(ep) = 3
count2(sp) = 1
tcl8.6.8> parray count3
count3(ep) = 4
count3(sp) = 2
However, please explain exactly what you mean by "dynamically creating a Tcl array". Do you really want three separate arrays or could you have one array with more names, like this:
set num 0
foreach i {1 2 3} {
set count($i,sp) $num
incr num
set count($i,ep) [expr $num+1]
}
tcl8.6.8> parray count
count(1,ep) = 2
count(1,sp) = 0
count(2,ep) = 3
count(2,sp) = 1
count(3,ep) = 4
count(3,sp) = 2
If you can avoid using a dynamic variable name like that, do so; they're often more trouble than they're worth. (You can use “composite” element names like $i,sp instead.) Otherwise — perhaps because of other code that accesses the array — the simplest way of handling them is to use upvar to make an alias to the variable with a fixed name. In particular, upvar 0 makes an alias to a variable in the same scope:
set num 0
foreach i {1 2 3} {
upvar 0 count$i ary
set ary(sp) {$num}
incr num
set ary(ep) [expr $num+1]
}
The only problem with upvar 0 is that you can't really undo it; that's why you almost always only use it within a procedure so the aliasing goes away naturally when the procedure exits.
Variable aliases are extremely efficient within the context of a procedure, substantially more so than using compound variable names in multiple places.
Also, {$num} looks suspicious. It's not wrong code in that it has a correct interpretation, but might not do what you expect and is often indicative of a problem, as $num isn't substituted. You might prefer [list $num].
You might enjoy using a dict instead of an array:
set count {}
set num 0
foreach i {1 2 3} {
dict set count $i sp $num
incr num
dict set count $i ep [expr {$num + 1}]
}
set count ;# -> 1 {sp 0 ep 2} 2 {sp 1 ep 3} 3 {sp 2 ep 4}
dict get $count 3 ep ;# -> 4

Cycle through variables incremented by a digit

I have an Access form where a bunch of sections are repeated, ex: Name, Age, Gender. The variable names for these text boxes are: Name1, Name2, ...; Age1, Age2, ...; etc.
I want to store all these values in an Array after a button is pressed. Instead of hardcoding all the variable names, I was wondering if there is a way to cycle through these in a for loop e.g.:
For i = 1 to 4
ArrayName(i) = ("Name" & i).value
ArrayAge(i) = ("Age" & i).value
ArrayGender(i) = ("Gender" & i).value
next i
I can get the string Name1 by ("Name" & i) but when I add .value after it, it doesn't seem to work.
I have also tried storing the variable name as a string into another array and then trying to use that array element to get the value, but that doesn't work either.
The error is because code is just building a string "Name1" and string does not have Value property. Consider:
Me.Controls("Name" & i).Value
or simplify with:
Me("Name" & i)
Value is default property so don't have to reference. However, the Me qualifier is important, otherwise the array will just populate with the control's name "Name1", not the control's value.
Arrays are 0-base by default which means the element index begins with 0 so iterating 1 to 4 to reference array elements will not provide correct results. Consider:
ArrayName(i - 1) = Me("Name" & i)
Otherwise, declare arrays as 1-base with Option Base 1 in module header.
Instead of 3 1-dimension arrays, a single 2-dimension array might serve.
Dim aryD(4, 3) As Variant, x As Integer, y As Integer
For x = 1 To 4
For y = 1 To 3
aryD(x - 1, y - 1) = Me(Choose(y, "Name", "Age", "Gender") & x)
Next
'verify array elements values
Debug.Print aryD(x - 1, 0) & " : " & aryD(x - 1, 1) & " : " & aryD(x - 1, 2)
Next

to_s method returning an unwanted "\"

I wrote a method that takes an array of numbers, adds the number 2 to it, and then returns an array of strings.
def add_two(array)
new_array = array.map{|x| "#{x} + 2 = #{x + 2}"}
new_array.to_s
end
The following is a test result:
I have an unwanted \ in my return. I am trying to figure out where the \ is coming from. Can someone point me in the right direction?
It is coming from to_s that you have at the end. You are converting an array of strings (which is presumably already what you want) into a single string that contains double quotations (which must be escaped by \). To fix it, just remove your line with to_s.
Its not adding extra \s. \ is escape character to escape " which is part of the result String. Here:
a = add_two(array)
# => "[\"1 + 2 = 3\", \"2 + 2 = 4\", \"3 + 2 = 5\"]"
puts a
# ["1 + 2 = 3", "2 + 2 = 4", "3 + 2 = 5"]
or directly:
puts add_two(array)
# ["1 + 2 = 3", "2 + 2 = 4", "3 + 2 = 5"]

return list of arrays

where is the difference in TCL TK with list and array ?
I created a list of 3 arrays.
like this one in a loop
set x($idx) 1
incr idx
and later i want to return the "ret" object
list set ret { $x $x2 $x3 }
and parse them again with
lassign $data x x2 x3
but this wont work... :(
could someone please help me again.. damn tcl tk... :D:D
correct me if im not right, its not possible to build a 2dim list or array ?
Your array is called x - you can refer to its elements by set x(1) , set x(2) etc. $x2 and $x3 have no meanings in this case.
If you want a 2 dimensional array, you can simulate it in TCL as follows:
set a(1,1) 0 ;# set element 1,1 to 0
set a(1,2) 5 ;# set element 1,2 to 5
It might be easier if you just use a list of lists
set l1 [list a b c]
set l2 [list d e f]
set lol [list $l1 $l2]
You can use array get/set to pass arrays as procedure arguments / return values. For example:
proc someProc {arr} {
array set x $arr
set x(5) 0
return [array get x]
}
Example of usage:
% set a(0) -1
% set a(1) 1
% parray a
a(0) = -1
a(1) = 1
% array set b [someProc [array get a]]
% parray b
b(0) = -1
b(1) = 1
b(5) = 0

perl - how do you extract all elements of an array except the last?

I need to extract all elements in an array except the last and store them in a scalar for later use.
At first, I thought this would be possible using array slices, but it appears that you cannot count backwards.
For example:
my $foo = ($bar[0..-2]);
or
my $foo = ($bar[-2..0]);
Any help would be greatly appreciated as this is starting to drive me insane, and I have been unable to find a solution elsewhere or by experimenting.
Oskar
my $foo = join ',', #bar[0..$#bar-1];
will concatenate (by comma) all elements of the array #bar except the last one into foo.
Regards
rbo
my #foo = #bar;
pop #foo;
or
my #foo = #bar[ -#bar .. -2 ];
or if it's ok to change #bar, just
my #foo = splice( #bar, 0, -1 );
#foo = #bar[0 .. $#foo - 1];
If you want to create a head-scratcher:
my #x = (1, 2, 3);
print "#x[-#x .. -2]";
This will store all array elements, except for the last, into a scalar. Each array element will be separated by a single space.
use strict;
use warnings;
my #nums = 1 .. 6;
my $str = "#nums[0 .. $#nums - 1]";
print $str;
__END__
1 2 3 4 5
Don't you really want to store the elements into another array? If you store them in a scalar, it can be problematic to retrieve them. In my example above, if any element of the array already had a single space, you would not be able to properly reconstruct the array from the scalar.

Resources