return list of arrays - 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

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

R Accessing vector inside list inside Array

I have a very long Array (1955x2417x1) in R where each position stores a list of two vector (named "max" and "min") of length 5.
I would like to find a simple way to create a multidimensional array (dim 1955x2417x5) where each position holds a single value from vector "max"
I have looked at answers such as array of lists in r
but so far without success.
I know I can access the list in each position of the array using
myarray[posX, PosY][[1]][["max"]]
but how to apply that to the whole Array?
SO far I have tried
newArray <- array( unlist(myarray[][[1]][["max"]]), c(1955, 2417, 5))
and
NewArray <-parApply(cl, myarray, c(1:2), function(x) {
a=x[[1]][["max"]]
} )
but the results are not right.
Do you have any suggestion?
Let
e <- list(min = 1:3, max = 4:6)
arr <- array(list(e)[rep(1, 8)], c(2, 4))
dim(arr)
# [1] 2 4
Then one option is
res <- apply(arr, 1:2, function(x) x[[1]][["max"]])
dim(res)
# [1] 3 2 4
and, if the order of dimensions matters,
dim(aperm(res, c(2, 3, 1)))
# [1] 3 2 4

Print specific parts of a cell as strings in matlab?

I have the following matrix array B :
B=[1 2 3; 10 20 30 ; 100 200 300 ; 500 600 800];
Which through a code is combined to form possible combinations between the values. The results are stored in cell G. Such that G :
G=
[1;20;100;500]
[0;30;0;800]
[3;0;0;600]
.
.
etc
I want to format the results based on which value from B is chosen :
[1 2 3] = 'a=1 a=2 a=3'
[10 20 30] = 'b=1 b=2 b=3'
[100 200 300]= 'c=1 c=2 c=3'
[500 600 800]= 'd=1 d=2 d=3'
Example, using the results in the current cell provided :
[1;20;100;500]
[0;30;0;800]
[3;0;0;600]
Should print as
a=1 & b=2 & c=1 & d=1
a=0 & b=3 & c=0 & d=3 % notice that 0 should be printed although not present in B
a=3 & b=0 & c=0 & d=2
Note that the cell G will vary depending on the code and is not fixed. The code used to generate the results can be viewed here : Need help debugging this code in Matlab
Please let me know if you require more info about this.
You can try this:
k = 1; % which row of G
string = sprintf('a = %d, b = %d, c = %d, d = %d',...
max([0 find(B(1,:) == G{k}(1))]), ...
max([0 find(B(2,:) == G{k}(2))]), ...
max([0 find(B(3,:) == G{k}(3))]), ...
max([0 find(B(4,:) == G{k}(4))]) ...
);
For instance, for k = 1 of your example data this results in
string =
a = 1, b = 2, c = 1, d = 1
A short explanation of this code (as requested in the comments) is as follows. For the sake of simplicity, the example is limited to the first value of G and the first line of B.
% searches whether the first element in G can be found in the first row of B
% if yes, the index is returned
idx = find(B(1,:) == G{k}(1));
% if the element was not found, the function find returns an empty element. To print
% a 0 in these cases, we perform max() as a "bogus" operation on the results of
% find() and 0. If idx is empty, it returns 0, if idx is not empty, it returns
% the results of find().
val = max([0 idx])
% this value val is now formatted to a string using sprintf
string = sprintf('a = %d', val);

array of lists in r

Suppose if I want to have 10 element array each element is a list/map. I am doing this:
x = array(list(), 10)
x[1][[ "a" ]] = 1
Warning message:
In x[1][["a"]] = 1 :
number of items to replace is not a multiple of replacement length
>
Is this the right approach? I want each element of the array to be a map.
What you're calling an "array" is usually just called a list in R. You're getting tripped up by the difference between [ and [[ for lists. See the section "Recursive (list-like) objects" in help("[").
x[[1]][["a"]] <- 1
UPDATE:
Note that the solution above creates a list of named vectors. In other words, something like
x[[1]][["a"]] <- 1
x[[1]][["b"]] <- 1:2
won't work because you can't assign multiple values to one element of a vector. If you want to be able to assign a vector to a name, you can use a list of lists.
x[[1]] <- as.list(x[[1]])
x[[1]][["b"]] <- 1:2
If you really want to do this, then, because the elements of the lists in each element of the array do not have names, you can't index by a character vector. In your example, there is no x[1][[ "a" ]]:
> x[1][[ "a" ]]
NULL
If there are no names then you need to index by a numeric:
> x[1][[ 1 ]] <- 1
[1] 1
It would seem more logical to have a list though than an array:
> y <- vector(mode = "list", length = 10)
> y
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
....

Dual array correspondance

I just found myself in a position where I have two arrays in Tcl.
I'm given $W_Array and $P_Array.
I need to traverse through one array not knowing what the size of each one is before hand, and execute a command only when there is a value for both arrays. Yes the array lengths could be different.
What is the best way of doing this?
The other answers jumped to using lists, I presume you mean Tcl's array, which are also called hash maps or associative arrays.
I think you're asking for something like:
array set a1 {a 1 b 2 c 3 d 4 e 5}
array set a2 {z 0 x 1 b 2 e 99}
foreach n [array names a1] {
if {[info exists a2($n)]} {
puts "Do something with $a1($n) and $a2($n)"
}
}
# FOREACH LOOP RESULTS IN THESE TWO PRINTOUTS
Do something with 5 and 99
Do something with 2 and 2
Not sure exactly what you mean by "a value for both arrays", but tcl's foreach supports iteration over multiple arrays at once... so you can say e.g.
foreach w $W_Array p $P_Array {
if {$w == $val && $p == $val} {
...
}
}
When the arrays are not of the same length, foreach will return all values from the longest array and the empty value {} for the missing elements in any shorter arrays.
Use llength command to find out if the arrays contain a value.
if {[llength $W_Array] > 0 && [llength $P_Array] > 0} {
# Do something
}

Resources