How to combine two list which are in a single list in Tcl? - concatenation

set a {1 3}
set b {}
set c_num {2 10 15 30}
lappend a $c_num
set d [concat $a $b]
puts $d
I want to combine this a and b set but the values should be separated.
from above code I get output as 1 3 {2 10 15 30}
instead I want output as 1 3 2 10 15 30
if there any solution please guide.

To change $d's value from 1 3 {2 10 15 30} to 1 3 2 10 15 30, there are a few ways.
One seemingly simple way is using join
join $d
--> 1 3 2 10 15 30
...but this join is actually a string command. To illustrate further, add a second argument to join and see how often the joining character appears.
join $d "#"
--> 1#3#2 10 15 30
Because Tcl doesn't have strict typing, a string can often be used as an argument to a list command (like lindex or llength). It's always more memory efficient to avoid converting values from strings to lists.
The concat command is a list command to form a new list from its arguments. Using the {*} operator converts the elements of a list into individual arguments.
concat {*}$d
--> 1 3 2 10 15 30
The best solution would be to avoid needing to use join or concat at all. Append multiple arguments to your list with the {*} operator instead of appending a list to a list.

You have a list of lists and you want to make a list of base elements? Try concat {*}$a. In this case, you can combine that with concatenating the list in $b; nested calls to concat can be simplified.

Related

Merge multiple arrays of unique occurrences

I want to merge multiple arrays of unique occurrences to a single array. To get the arrays in the first place I use this code, where image series is a slice from a tiff image imported using imread:
a = unique(img_series);
occu = [a,histc(img_series(:),a)];
I do that multiple times, because the tiff image I'm using has multiple hundred images stacked, which my RAM will not support to import at once. So each 'occu' looks something like this (first number is the unique value, second number is the number of occurrences):
occu1 occu2 .....
0 1 1 2
12 1 10 1
14 1 12 1
15 1 14 2
.. .. .. .. .....
Now I want to merge them all together, or better merge them in each iteration, when I'm reading another stacked image.
The merged results should be a 2D matrix similar to the one above. The number of occurrences of the same values should be added to one another, as this is the whole point of counting them. So the result of the above example should be this:
occu_total
0 1
1 2
10 1
12 2
14 3
15 1
.. ..
I found the join command, but that one does not seem to work here. I guess I could do it the long way of searching the matching number and add the occurrences together and so on, but there must be a quicker way of doing it.
A = [0 1;12 1; 14 1;15 1];B = [1 2;10 1;12 1;14 2];
tmp = [A;B]; %// merge arrays into a single one
tmp(:,1) = tmp(:,1)+1;%// remove zero occurrences by adding 1 to everything
C = accumarray(tmp(:,1),tmp(:,2)); %// add occurrences all up
D = [1:numel(C)].'; %// create numbered array
E = [D C];
E((C==0),:)=[]; %// get output
E(:,1) = E(:,1)-1;%// subtract the 1 again
E =
0 1
1 2
10 1
12 2
14 3
15 1
Job for accumarray. This takes the first argument as your dictionary key, and adds the values of the each key together. The addition and subtraction of 1 is done because 0 cannot be an index in MATLAB. To circumvent this (assuming you have no negative numbers), you can simply add 1 and remove that afterwards, shifting all your indices to positive integers. If you hit negative numbers, subtract tmp(:,1) = min(tmp(:,1)+1 and add E(:,1) = min(tmp(:,1)-1

Get values of columns of a file with tabs and newlines separating them read via bash script to an array

Hello I have been trying to get the numbers in the columns of a file for two days by reading a file via a bash script. Here is the file sample.txt
1 1 1 1 1
9 3 4 5 5
6 7 8 9 7
3 6 8 9 1
3 4 2 1 4
6 4 4 7 7
By column I mean i.e the first column is
1
9
6
3
3
6
I need to have the column elements each be in a given array col1 or col2 etc so that I can manipulate the values further.
Here's what I have done so far using while loop I have read the contents of the file assigning them each line to an array.
If I set IFS=$'\n'
while read -a line
do
IFS=$'\n'
#I can get the whole column 1 with this
echo ${line[0]}
#for column 2 I can get it by this an the others too
echo ${line[1]}
done < sample.txt
Now that may seem good as i thought but since I want to calculate averages of the columns putting in another loop like a for loop becomes impossible since ${line[0]} has all the elements in column 1 but they are all as a single string (i have tried to observe) that cannot be acted upon.
What would be the best way to get those elements be members of a given array and then compute the averages on them. help appreciated .
In bash I'd write
declare -A cols
n=0
while read -ra fields; do
for ((i=0; i<${#fields[#]}; i++)); do
cols[$i,$n]=${fields[i]}
((n[i]++))
done
done < sample.txt
read -a reads the fields of the line into the named array.
I'm using cols as an associative array to fake a multi-dimensional array. That's way easier to deal with than using a dynamic variable name:
eval "column${i}[$n]=\${fields[$i]}"

Find elements in array those have come two times in array

Given A = [3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 8]
Output B = [3 4 5 6 8]
Is there a Matlab function or command to get this result? I am new to Matlab. Just now I am doing it going through for each element and keeping a counter for it. I have very big array so this is taking too much time.
Use a combination of unique and histc:
uA = unique(A); %// find unique values
B = uA(histc(A, uA)>=2); %// select those that appear at least twice
The above code gives the values that appear at least twice. If you want values that appear exactly twice, replace >= by ==.

Matlab : Matrix indexing Logic

i am doing very simple Matrix indexing examples . where code is as give below
>> A=[ 1 2 3 4 ; 5 6 7 8 ; 9 10 11 12 ]
A =
1 2 3 4
5 6 7 8
9 10 11 12
>> A(end, end-2)
ans =
10
>> A(2:end, end:-2:1)
ans =
8 6
12 10
here i am bit confused . when i use A(end, end-2) it takes difference of two till first column and when there is just one column left there is no further processing , but when i use A(2:end, end:-2:1) it takes 6 10 but how does it print 8 12 while there is just one column left and we have to take difference of two from right to left , Pleas someone explain this simple point
The selection A(end, end-2) reads: take elements in last row of A that appear in column 4(end)-2=2.
The selection A(2:end, end:-2:1) similarly reads: take elements in rows 2 to 4(end) and starting from last column going backwards in jumps of two, i.e. 4 then 2.
To check the indexing, simply substitute the end with size(A,1) or size(A,2) if respectively found in the row and col position.
First the general stuff: end is just a placeholder for an index, namely the last position in a given array dimension. For instance, for an arbitrary array A(end,1) will pick the last element in column 1, and A(1,end) will pick the last element in the first row.
In your example, A(end, end-2) picks an element in the last row two columns before the last one.
To interpret a statement such as
A(2:end, end:-2:1)
it might help to substitute end with the actual index of the last row/column elements, so this is equivalent to
A(2:3, 4:-2:1)
Furthermore 4:-2:1 is equivalent to the list 4,2 since we are instructing to make the list starting at 4, decreasing in steps of 2, up to (minimum) 1. So this is equivalent to
A([2 3],[4 2])
Finally, the following combination of indices is implied by A([2 3],[4 2]):
A(2,4) A(2,2)
A(3,4) A(3,2)

How can I concatenate ranges of numbers into an array in MATLAB?

For example, I want to combine two ranges of numbers like this:
1 2 3 4 5 11 12 13 14 15 16 17 18 19 20
So, I tried:
a = 1:5,11:20
but that didn't work.
I also want to do this in a non-hardcoded way so that the missing 5 elements can start at any index.
For your example, you need to use square brackets to concatenate your two row vectors:
a = [1:5 11:20];
Or to make it less hardcoded:
startIndex = 6; %# The starting index of the 5 elements to remove
a = [1:startIndex-1 startIndex+5:20];
You may also want to check out these related functions: HORZCAT, VERTCAT, CAT.
There are a few other ways you could do this as well. For one, you could first make the entire vector, then index the elements you don't want and remove them (i.e. set them to the empty vector []):
a = 1:20; %# The entire vector
a(6:10) = []; %# Remove the elements in indices 6 through 10
You could also use set operations to do this, such as the function SETDIFF:
a = setdiff(1:20,6:10); %# Get the values from 1 to 20 not including 6 to 10

Resources