Intertwining 3 arrays in matlab / octave to get correct pattern - arrays

I know I can intertwine 2 arrays by
C = [A(:),B(:)].'; %'
D = C(:)
But how can I intertwine 3 arrays with a (pendulum type of pattern going back and forth) See image below with arrows showing the intertwining path pattern I'm trying to get (each column is an array). Also the number pattern I'm trying to get is also next to it, in one large column. Please note the numerical values are just examples to make it easier to read. the numerical values could be decimals also
I tried the code below but the pattern is incorrect.
A=[1,2,3,4,5]
B=[10,20,30,40,50,60,70,80,90]
C=[100,200,300,400,500]
D = [A(:),B(:),C(:)].'; %'
E = D(:)
I get an error in the D array due to the fact that the B array is a larger size than A and C but the number pattern is also not following the pattern I'm trying to get.
1
10
100
2
20
200
3
30
300
4
40
400
5
50
500
error: horizontal dimensions mismatch (5x1 vs 9x1)
The pattern from the 3 arrays I'm trying to get is below.
Please note the numerical values are just examples to make it easier to read. the numerical values could be decimals also
1
10
100
20
2
30
200
40
3
50
300
60
4
70
400
80
5
90
500
PS: I'm using Octave 3.8.1 which is like matlab

Have you tried the following?
D = zeros(4 * size(A, 2) - 1, 1); % initialization
D(1 : 4 : end) = A;
D(2 : 2 : end) = B;
D(3 : 4 : end) = C;

Related

Matlab: Creating a blockwise permutation

I have a vector from 1 to 40 and want to shuffle it in such a way that each block of four integers (ten blocks in total) are shuffled only with themselves.
For example: 3 4 2 1 | 7 6 5 8 | 9 11 10 12 | ...
My original idea was to append ten permutation vectors to eachother and then add a 1 to 40 vector to the big permutation vector, but it didn't work at all as expected and was logically wrong.
Has anyone an idea how to solve this?
data = 10:10:120; % input: values to be permuted
group_size = 4; % input: group size
D = reshape(data, group_size, []); % step 1
[~, ind] = sort(rand(size(D)), 1); % step 2
result = D(bsxfun(#plus, ind, (0:size(D,2)-1)*group_size)); % step 3
result = result(:).'; % step 4
Example result:
result =
20 10 30 40 60 50 70 80 110 100 120 90
How it works
Reshape the data vector into a matrix D, such that each group is a column. This is done with reshape.
Generate a matrix, ind, where each column contains the indices of a permutation of the corresponding column of D. This is done generating independent, uniform random values (rand), sorting each column, and getting the indices of the sorting (second output of sort).
Apply ind as column indices into D. This requires converting to linear indices, which can be done with bsxfun (or with sub2ind, but that's usually slower).
Reshape back into a vector.
You can use A = A(randperm(length(A))) to shuffle an array.
Example in Octave:
for i = 1:4:40
v(i:i+3) = v(i:i+3)(randperm(4));
end

Group two non-adjacent columns into 2d array for Excel VBA Script

I think this question might be related to Ms Excel -> 2 columns into a 2 dimensional array but I can't quite make the connection.
I have a VBA script for filling missing missing data. I select two adjacent columns, and it finds any gaps in the second column and linearly interpolates based on (possibly irregular) spacing in the first column. For instance, I could use it on this data:
1 7
2 14
3 21
5 35
5.1
6 42
7
8
9 45
to get this output
1 7
2 14
3 21
5 35
5.1 35.7 <---1/10th the way between 35&42
6 42
7 43 <-- 1/3 the way between 42 & 45
8 44 <-- 2/3 the way between 42 & 45
9 45
This is very useful for me.
My trouble is that it only works on contiguous columns. I would like to be able to select two columns that are not adjacent to each other and have it work the same way. My code starts out like this:
Dim addr As String
addr = Selection.Address
Dim nR As Long
Dim nC As Long
'Reads Selected Cells' Row and Column Information
nR = Range(addr).Rows.Count
nC = Range(addr).Columns.Count
When I run this with contiguous columns selected, addr shows up in the Locals window with a value like "$A$2:$B$8" and nC = 2
When I run this with non-contiguous columns selected, addr shows up in the Locals window with a value like "$A$2:$A$8,$C$2:$C$8" and nC = 1.
Later on in the script, I collect the values in each column into an array. Here's how I deal with the second column, for example:
'Creates a Column 2 (col1) array, determines cells needed to interpolate for, changes font to bold and red, and reads its values
Dim col2() As Double
ReDim col2(0 To nR + 1)
i = 1
Do Until i > nR
If IsEmpty(Selection(i, 2)) Or Selection(i, 2) = 0 Or Selection(i, 2) = -901 Then
Selection(i, 2).Font.Bold = True
Selection(i, 2).Font.Color = RGB(255, 69, 0)
col2(i) = 9999999
Else
col2(i) = Selection(i, 2)
End If
i = i + 1
Loop
This is also busted, because even if my selection is "$A$2:$A$8,$C$2:$C$8" VBA will treat Selection(1,2) as a reference to $B$2, not the desired $C$2.
Anyone have a suggestion for how I can get VBA to treat non-contiguous selection the way it treats contiguous?
You're dealing with "disjoint ranges." Use the Areas collection, e.g., as described here. The first column should be in Selection.Areas(1) and the second column should be in Selection.Areas(2).

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

Working with arrays in VBA memory and avoiding loops using vectorization

I am versed in MATLAB but find myself working in VBA these days as MATLAB is less accessible to me and I struggle with trying to do stuff in VBA (like vectorization) that I could easily handle in MATLAB.
Lets say I have a data table in excel of the following form:
record startDate endDate count
1 100 103 10
2 98 102 5
3 101 104 4
I would like to do all my processing in memory (avoiding loops) and then output results file that looks like this:
1 2 3 Sum
98 0 5 0 5
99 0 5 0 5
100 10 5 0 15
101 10 5 4 19
102 10 5 4 19
103 10 0 4 14
104 0 0 4 4
Basically, I start with earliest date and loop through the latest date and then check to see if each date is included in the date window for each record and if it is I apply the record count to that day and then sum them up.
I created the included output using a simple worksheet function, but I would like to be able to replicate the process in VBA specifically avoiding looping at least reducing to 1 loop instead of embedded loops.
If I were in MATLAB I would find the logical array that meets a condition, for example:
numDays = 7;
numRecords = 3;
startDate = [100; 98; 101];
endDate = [103; 102; 104];
dateVector = [98; 99; 100; 101; 102; 103; 104];
count = [10; 5; 4];
dateLogic = logical(numDays,numRecords);
for d = 1:numDays
dateLogic(d,:) = dateVector(d) >= startDate(:,1) & dateVector(d) <= endDate(:,1)
end
countMatrix = dateLogix * count';
Sum = sum(countMatrix,2);
This would give me a logical matrix of zeros and ones that I can cross multiply with count vector to get my counts and ultimately my Sum vector. I believe I could even use a bsxfun to remove the loop on days.
Please excuse any potential syntax errors as I do not have access to MATLAB right now.
Anyway, how can I do something similar in VBA. Is there an equivalent colon notation to reference the entire range of columns or rows in an array. I will be applying to large data set so efficiency is of the essence. The more I can do in memory before pasting the better.
Thanks in advance.
Here's one possibility, try with sampe data in A1:A4 of a new workbook.
Sub NewTable()
Set Table = Sheet1.[a2:d4]
With Application
Record = .Transpose(.Index(Table, , 1))
FirstDate = .Transpose(.Index(Table, , 2))
LastDate = .Transpose(.Index(Table, , 3))
Count = .Transpose(.Index(Table, , 4))
Dates = .Evaluate("row(" & .Min(FirstDate) & ":" & .Max(LastDate) & ")")
Values = .PV(, Count, .PV(, .GeStep(Dates, FirstDate), .GeStep(LastDate, Dates)))
Sum = .MMult(Values, .Power(.Transpose(Record), 0))
End With
Sheet1.[F1].Offset(, 1).Resize(, UBound(Values, 2)) = Record
Sheet1.[F2].Resize(UBound(Dates)) = Dates
Sheet1.[G2].Resize(UBound(Values), UBound(Values, 2)) = Values
Sheet1.[G2].Offset(, UBound(Values, 2)).Resize(UBound(Dates)) = Sum
End Sub

Associating / linking an array column with another column in the array

I have an array that has some calcultations done on the second column. I would like the values from the third column to follow/be linked to the second column.
Test Code:
a1= [1,10,-11;
2,70,232;
3,33.2,-33;
4,40,44;]
a2calc=abs(a1(:,2)-max(a1(:,2))) %calculation
a2=[a1(:,1),a2calc,a1(:,3)] %new array
Example:
original a1 Array
1 10 -11
2 70 232
3 33.2 -33
4 40 44
a2 Array after column 2 calculations looks like this
1 60 -11
2 0 232
3 36.8 -33
4 30 44
I'm trying to get the final array to look like this (column 3 values follow / are linked to the second column)
1 60 232
2 0 -11
3 36.8 44
4 30 -33
What I'm having problems with is I'm not sure if I should use the index values of column 2 and if so how I can get it to look like the final output array I included in the question.
I might be wrong here, but it looks to me like the logic is:
After calculating the second column, change the order of the third column so that the third column is sorted the same way as the second. To see what I mean:
This represents the two columns, numbered from highest to lowest:
A = 1 1
4 3
2 2
3 4
If I understand it right, you want the resulting matrix to be
A = 1 1
4 4
2 2
3 3
If this is the right logic then you should check out sort with two outputs. You can use the second output to index the third column.
[~, idx] = sort(A(:, 2));
sorted_3 = sort(A(:, 3));
A(idx, 3) = sorted_3;
The output from this is:
A =
1.00000 60.00000 232.00000
2.00000 0.00000 -33.00000
3.00000 36.80000 44.00000
4.00000 30.00000 -11.00000
Good luck!

Resources