How do I split a text file into blocks using Perl? - arrays

I have a data file with lines like this:
A1 2 3 4 5
B 1 2 4
B 7 8 9
A6 7 8 9
B 1 2 3
B 5 6 7
A3 6 9 7
B 2 3 3
B 5 6 6
Using Perl, how do I split the file into a set of arrays (or any other data structure) when the parser hits a /^A/ please?
so I end up with
array1:
A1 2 3 4 5
B 1 2 4
B 7 8 9
array2:
A6 7 8 9
B 1 2 3
B 5 6 7
etc.
Many thanks.

I had to rewrite the answer (after rewritten question)
#arrays = ();
while (<>) {
push(#arrays, []) if /^A/;
push(#{$arrays[-1]}, $_)
}

It is at times like this when I wish $/ could be more than just a string. Nevertheless, there are workarounds.
One could slurp the file in and process with a lookahead assertion. The example below simply prints each string delimited with << >>, but the basic idea is the same regardless of what you want to do with the data:
$ perl -0777 -wE 'say "<<$_>>" for split /(?=^A)/m, <>' file.txt
<<A1 2 3 4 5
B 1 2 4
B 7 8 9
>>
<<A6 7 8 9
B 1 2 3
B 5 6 7
>>
<<A3 6 9 7
B 2 3 3
B 5 6 6
>>

Related

Create two vectors in matlab using for loop

I am trying to create two vectors
first:
[ 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 ]
second:
[ 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1 ]
I had almost no problems with the first one:
i = 1:10;
for t = 1: 2*length(i)-1
y1(t) = abs(length(x)-t)+1;
end
But there are some problems with the second...
Does anyone have any idea how I can create it using the same for loop?Thanks in advance
If you want to do it with a loop:
N = 10;
for t = 1:2*N-1
y2(t) = -abs(t-N)+N;
end
But its probably easier to use the following, first make an array 1:N, and then concatenate the array N-1:-1:1:
y2 = [1:N, N-1:-1:1]

Using multiple indicies to grab values from 2D MATLAB array without returning all combinations [duplicate]

This question already has an answer here:
3d matrix: how to use (row, column) pairs with 3rd dimension wildcard in MATLAB?
(1 answer)
Closed 5 years ago.
I am trying to get a few values from a 2D matrix
Consider the starting matrix:
>> test = randi(10,10)
test =
10 4 8 7 10 4 2 8 4 1
6 5 6 5 5 2 10 4 7 6
7 2 5 4 1 1 3 7 6 1
1 3 3 9 9 5 10 4 6 9
9 1 8 4 7 2 3 7 3 10
8 10 3 9 4 8 4 1 3 1
2 7 1 8 10 4 1 10 5 10
6 10 8 9 3 9 7 9 3 1
4 2 7 6 7 8 2 8 9 7
6 10 8 7 7 6 1 9 10 8
What I want to do is grab elements (1,4);(2,5);and(3,6) only
So I try
test([1,2,3],[4,5,6])
but that returns all combinations of the two indicies!
ans =
6 3 1
1 2 4
8 4 8
Without this intermediate step, how do I do what I want in one line? There must be a way.
I cannot use the intermediate step because in actuality, my matrix is very large and so are my indices lengths so I will run out of memory.
You can do this using sub2ind as was already pointed out at mathworks:
test(sub2ind(size(test),[1,2,3],[4,5,6]))
Applied to 3D
test = randi(10,10,10,10);
test(sub2ind(size(test),[1,2,3],[4,5,6], [3,3,3]))

MATLAB: how to pass in the diagonal of a matrix as an argument in another matrix?

Let c be 2D array, and x and y be 1D arrays of the same length (for instance, let's have x=1:7 and y=3:9).
I need to find a way to pass in arguments from x and y in the way I will describe below.
If I put simply c(x,y) it will give a 7 by 7 matrix. I don't want that.
Instead, I want to pass in the diagonal of the [x y] matrix: ((x(1), y(1)), (x(2), y(2))...(x(7), y(7)). Is there a way to do this without a for loop or any iterative statement?
You are looking for sub2ind function
res = c( sub2ind(size(c), x, y ) )
There's an easier way. If you're looking for a diagonal, use diag. If you have a matrix c:
c =
5 8 4 2 9 1 6 1 1
9 8 7 5 9 3 2 7 5
2 3 9 10 2 1 4 2 2
3 2 9 2 4 4 7 2 4
3 9 10 8 7 5 2 1 8
5 6 3 7 6 1 10 5 2
6 1 7 3 10 8 2 4 2
you can find the main diagonal by using diag with no extra arguments:
>> diag(c)
ans =
5
8
9
2
7
1
2
The second argument, though, indicates which diagonal you want as an offset from the main diagonal. So the default diagonal is equal to 0. If you want the diagonal starting at c(1,3), that's 2 above the main diagonal, so
>> diag(c,2)
ans =
4
5
2
4
2
5
2
Similarly, if you want the diagonal starting at c(4,1), the offset is -3:
>> diag(c,-3)
ans =
3
9
3
3

Matlab- Combinations for subsets of a set

Hi may I know how i can perform this using matlab?
I tried nchoosek but only works on 1 type of combination. I would like to output all together in array
Let S={a,b,c,d,e}
I would like to get combinations as such which start from 3 combinations:
the 3-combinations : {a,b,c} , {a,b,d} , {a,b,e} , {a,c,d} , {a,c,e} , {a,d,e}
the 4-combinations : {a,b,c,d} , {a,b,c,e} , {a,c,d,e}
the 5-combinations : {a,b,c,d,e}
So the output would be like this:
{a,b,c} {a,b,d} {a,b,e} {a,c,d} {a,c,e} {a,d,e}{a,b,c,d} {a,b,c,e} {a,c,d,e}{a,b,c,d,e}
Thanks
You can use a loop there or arrayfun which is just a compact way to express such a loopy approach and not a vectorized approach -
combs = arrayfun(#(x) nchoosek(S,x),3:numel(S),'Uniform',0)
The output would be a cell array with each cell representing values for each combination. So, when you run the code, you would get -
>> combs{1}
ans =
2 7 4
2 7 1
2 7 9
2 4 1
2 4 9
2 1 9
7 4 1
7 4 9
7 1 9
4 1 9
which would be your 3-combinations set.
>> combs{2}
ans =
2 7 4 1
2 7 4 9
2 7 1 9
2 4 1 9
7 4 1 9
would be your 4-combinations set and so on.

How can I create a 3D array by stenciling the columns of a 2D array in MATLAB?

Suppose I have a 2D array called A. I want to create a 3D array called B, whose "pages" are select columns of a stencil moving across A, column-by-column. For example, the first page of B might be the 1st, 3rd, and 5th columns of A. Then the second page would be the 2nd, 4th, and 6th columns of A, etc.
Anyone have an efficient way of doing this is MATLAB?
Thanks!
I am guessing you are looking for this -
%%// Given 2D array
A = randi(10,4,12)
t1 = reshape(A,size(A,1)*2,[]);
t2 = reshape(t1',size(A,2)/2,[],2); %%//'
B = permute(t2,[2 1 3]) %%// Output 3D array
Output -
A =
5 10 3 5 6 8 4 3 8 10 8 7
10 8 3 7 6 10 9 2 7 8 8 5
10 4 7 8 6 4 5 4 1 1 3 7
7 7 6 6 1 10 5 8 9 4 3 3
B(:,:,1) =
5 3 6 4 8 8
10 3 6 9 7 8
10 7 6 5 1 3
7 6 1 5 9 3
B(:,:,2) =
10 5 8 3 10 7
8 7 10 2 8 5
4 8 4 4 1 7
7 6 10 8 4 3
Of course, there is an alternative straight-forward approach for this special case -
B(:,:,1)=A(:,1:2:end);
B(:,:,2)=A(:,2:2:end);

Resources