Perl: array splitting and complex merging - arrays

I have the following string A B C D E F G H I J. I want to make an array out of it, so I use this
my #string = split/(\W)/, $text;
It works ok, and I get an array of 20 lines looking like this:
A
B
C
D
...
Now, I want to split this array in a given number of pieces (let's say 4 in this case), thus resulting I imagine in 4 smaller arrays of 5 lines each, looking like this #1 = A, ,B, ,C , #2 = ,D, ,E,, #3 = F, ,G, ,H and #4 = ,I, ,J,.
Finally, I want to interleave these 4 arrays in order to get an output array in which I first have the first line of each array, the the second line of each array, and so on... the final thing looking like this :
A
F
D
I
B
G
E
J
C
H
How to achieve this?

To make a slice of an array in Perl:
my #oldArray = (a, ,b, ,c, ,d, ,e, ,f, ,g, h, ,i, ,j, );
my #newArray1 = #oldArray[elemIndex1,elemIndex2,elemIndexN];
OR
my #newArray1 = #oldArray[firstElemIndex..lastElemIndex]
Where elemIndex is the index of the element you want in the newArray array.
firstElemIndex..lastElemIndex is used when you want consecutive indexes to be in the sliced array.
To add elements at the end of an array:
push(#interleavedArray,$newArray1[elemIndex]);
Where $newArray1[elemIndex] is the element from #newArray1 you want to add to #interleavedArray
To add elements in order:
Just do a for loop:
for my $index (0..3){
push(#interleavedArray,$newArray1[$index]);
push(#interleavedArray,$newArray2[$index]);
push(#interleavedArray,$newArray3[$index]);
push(#interleavedArray,$newArray4[$index]);
}

Related

Modifying a numpy array efficiently

I have a numpy array A of size 10 with values ranging from 0-4. I want to create a new 2-D array B from this with its ith column being a vector corresponding to the ith element of A.
For example, the value 1 as the first element of A would correspond to B having a column vector [0,1,0,0,0] as it's first column. A having 4 as its third element would correspond to B having it's 3rd column as [0,0,0,1,0]
I have the following code:
import numpy as np
A = np.random.randint(0,5,10)
B = np.ones((5,10))
iden = np.identity(5, dtype=np.float64)
for i in range(0,10):
a = A[i]
B[:,i:i+1] = iden[:,a:a+1]
print A
print B
The code is doing what it's supposed to be doing but I am sure there are more efficient ways of doing this. Can anyone please suggest some?
That could be solved by initializing an array of zeros and then integer-indexing into it with indices from A and assigning 1s, like so -
M,N = 5,10
A = np.random.randint(0,M,N)
B = np.zeros((M,N))
B[A,np.arange(len(A))] = 1

Select entries from matrices according to indices in another matrix in MATLAB

I have matrices:
a= 0.8147 0.1270 0.6324
0.9058 0.9134 0.0975
b= 0.2785 0.9649 0.9572
0.5469 0.1576 0.4854
0.9575 0.9706 0.8003
c = 0.1419 0.7922
0.4218 0.9595
0.9157 0.6557
and also I have another matrix
I= 1 3 1 1
2 1 3 2
I want to get d matrix such that
d= a(1,3) b(3,1) c(1,1)
a(2,1) b(1,3) c(3,2)
where indices come as two consecutive entries of I matrix.
This is one example I get. However, I get different size matrices for a,b,c,.. and I.
Added: I is m x (n+3) which includes indices, and other (n+2) matrices which have corresponding entries are X,A1,A2,...,An,Y. When n is given, A1,A2,...,An matrices are generated.
Can someone please help me to write Matlab code for this task?
You can do it with varargin. Assuming that your matrices are constructed such that you can form your desired output in the way you want (Updated according to Carmine's answer):
function out = IDcombiner(I, varargin)
out = zeros(size(I, 1), nargin-1);
idx = #(m, I, ii) (sub2ind(size(m), I(:, ii), I(:, ii+1)));
for ii = 1:1:nargin-1
out(:, ii) = varargin{ii}(idx(varargin{ii}, I, ii));
end
Now using this function you can make your selection on a flexible number of inputs:
out = IDcombiner(I, a, b, c)
out =
0.6324 0.9575 0.1419
0.9058 0.9572 0.6557
There is also a one-liner solution, which I do not recommend, since it dramatically decreases the readability of the code and doesn't help you gain much:
IDcombiner = #(I,varargin) ...
cell2mat(arrayfun(#(x) varargin{x}(sub2ind(size(varargin{x}), ...
I(:,x), I(:,x+1))), 1:nargin-1, 'UniformOutput', false));
Normally a matrix is not interpreted as a list of indices, but you can have this if you use sub2ind. To use it you need the size of the matrix you are addressing. Let's make an example starting with a:
a(sub2ind(size(a), I(:,1), I(:,2)))
The code does not change if you first assign the newly generated matrices to a variable name.
will use the column I(:,1) as rows and I(:,2) as columns.
To make the code more readable you can define an anonymous function that does this, let's call it idx:
idx = #(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))
So finally the code will be
d = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3))]
The code does not change if you first assign the newly generated matrices to a variable name.
Other details
Let's make an example with 2 central matrices:
a = rand(3,1) % 3 rows, 1 column
b = rand(3,3) % 3 rows, 3 columns
c = rand(3,3) % another squared matrix
d = rand(3,1) % 3 rows, 1 column
The definition of the anonymous function is the same, you just change the definition of the output vector:
output = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3)), d(idx(d,I,3))]
Keep in mind that following that pattern you always need a I matrix with (n_matrices + 1) columns.
Generalization
Let's generalize this code for a number n of central matrices of size rxr and for "side matrices" of size rxc. I will use some values of those parameters for this example, but you can use what you want.
Let me generate an example to use:
r = 3;
c = 4;
n = 3;
a = rand(r,c); % 2D array
b = rand(r,r,n); % 3D array, along z = 1:n you have 2D matrices of size rxr
c = rand(r,c);
I = [1 3 1 2 1 3; 2 1 3 1 1 1];
The code I wrote can easily be extended using cat to append matrices (note the 2 in the function tells MATLAB to append on the direction of the columns) and a for cycle:
idx = #(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))
d = a(idx(a,I,1));
for i = 1:n
temp = b(:,:,i);
d = cat(2,d,temp(idx(tmp,I,i+1)));
end
d = cat(2,d,c(idx(c,I,n+1)));
If you really don't want to address anything "by hand", you can use cell arrays to put all the matrices together and then cyclically apply the anonymous function to each matrix in the cell array.

Apply a function to three parallel array of arrays

I have three arrays of arrays like this:
catLabels = [catA, catB, catC]
binaryLabels = [binA, binB, binC]
trueLabels = []
trueLabels.extend(repeat(y_true_categories, len(binaryLabels)))
def binaryConversion(trueLabel, evalLabel, binaryLabel):
for true,eval, binary in zip(trueLabel, evalLabel, binaryLabel):
if eval == true:
binary.append(1)
else:
binary.append(0)
for x,y,z in zip(trueLabels,catLabels,binaryLabels):
binaryConversion(x, y, z)
Each of the values in catLabels and binLabels is an array. binLabels contain an array of empty arrays, each of which I want to fill in 1s and 0s lets say for example catA = [A B C A B D] and binA = []. trueLabels contains multiple arrays each of which are the same (y_true_categories, i.e. my true categorical labels [A C C B B D]. In this case, my binaryConversion function should fill in [1 0 1 0 1 1] for the array binA.
For some reason my current function is not achieving this and leaves each of bin A, binB, binC empty.
What am I doing wrong?
I have figured out the answer. The inner zip statement will not work because I start with empty binary labels, and zip only works when all the arrays you are zipping are of the same length. So I removed the binaryLabel from the zip function within binaryConversion(trueLabel, evalLabel, binaryLabel) and appended to each binaryLabel empty binary array inside the loop. In addition, I was appending 1s and 0s to the element-wise binary, instead of the actual empty array binaryLabel.
New code:
def binaryConversion(trueLabel, evalLabel, emptyBinaryArray):
for true,eval in zip(trueLabel, evalLabel):
if eval == true:
emptyBinaryArray.append(1)
else:
emptyBinaryArray.append(0)
for trueLabels,predictionLabels,emptyBinaryArray in zip(trueLabels,catLabels,binaryLabels):
binaryConversion(trueLabels, predictionLabels, emptyBinaryArray)

Selecting every other block of elements from MATLAB array

We all know how to select every other n element using index like A[1:n:end]. Suppose I have a 1000x1 array and I divide (conceptually) it into blocks of 5 elements, and I want to select every other block, i.e., to select A[1], A[2], A[3], A[4], A[5] and A[11], A[12], A[13], A[14], A[15], ..., you got the idea.
Of course I can generate an index array beforehand and use it, but I am wondering if there are more convenient ways.
So in effect you are trying to create a square wave indexing function, how about something like
n = 1:numel(A); %// assuming A is a vector (i.e. 1D)
w = 2^-3;
idx = sin(2*pi*w*n) > 0;
You then tune w to change block width.
Alternatively
w = 3
idx = floor(mod(0:n-1),2*w)/w);
You can reshape the array into a matrix:
A = rand(1000,1);
n = 5;
B = reshape(A,n,[]);
Now each column of B is a group:
B(:,1) == A(1:5)
B(:,2) == A(6:10)
...
From there you can select every other column of B the same way you would for a vector:
B = B(:,1:2:end);

How do I assign index entries found using matlab ismember to another array?

I have two vectors P and D. I have written the following code which looks at each element of D and then finds the same element in P (both have same elements just in different order) and returns the index of that element in P. The following code is able to do that.
for i=1:17
ind = find(ismember(P,D(i)));
ind
msgbox(sprintf('\n i is: %d\n',ind));
end
The problem is that I want each 'ind' value to be stored in an array.
for i=1:17
ind(i) = find(ismember(P,D(i)));
msgbox(sprintf('\n i is: %d\n',ind));
end
returns an error.
Is it possible assign find(ismember) to different entries of an array?
Thanks!
Edited:
My vectors P and D look as follows:
P = {'Fz' 'Fp1' 'Cz' 'T3' 'T4'}
D = {'T4' 'Cz' 'T3' 'Fp1' 'Fz'}
The error I'm getting at the moment is:
In an assignment A(:) = B, the number of elements in A and B must be the same.
You don't have to implement this yourself, ismember can already do it:
P = {'Fz' 'Fp1' 'Cz' 'T3' 'T4'};
D = {'T4' 'Cz' 'T3' 'Fp1' 'Fz'};
[~, ind] = ismember(D, P)
results in
ind =
5 3 4 2 1
But if you really want to do it yourself – your code basically works already
ind = zeros(size(D));
for i = 1 : numel(D)
ind(i) = find(ismember(P, D(i)));
end
and gives the same result.

Resources