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

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]))

Related

MQL5: How to Rank an Array's values

I used R and the rank function to create the following ranks for the original var x:
x average first last random max min
3 4.5 4 5 5 5 4
1 1.5 1 2 2 2 1
4 6.0 6 6 6 6 6
1 1.5 2 1 1 2 1
5 8.0 7 9 9 9 7
9 11.0 11 11 11 11 11
2 3.0 3 3 3 3 3
6 10.0 10 10 10 10 10
5 8.0 8 8 7 9 7
3 4.5 5 4 4 5 4
5 8.0 9 7 8 9 7
I am struggling to implement the min-version in MQL5. First, you probably need to sort the Array but you need to take care of the original order. How the ranks are assigned manually is quite logical but I have no clue how to implement this in MQL5.

How can I count number of occurrences of unique row in MATLAB ?

I have a matrix like following,
A =
1 2 3
4 5 6
7 8 9
10 11 12
4 5 6
7 8 9
4 5 6
1 2 3
I could extract unique rows in this matrix using command A_unique = unique(A,'rows') and result as follows
A_unique =
1 2 3
4 5 6
7 8 9
10 11 12
I need to find number of times each rows exists in the main matrix A
Some thing like following
A_unique_count =
2
3
2
1
How can I find count of unique rows? Can anyone help? Thanks in Advance
Manu
The third output of unique gives you the index of the unique row in the original array. You can use this with accumarray to count the number of occurrences.
For example:
A = [1 2 3
4 5 6
7 8 9
10 11 12
4 5 6
7 8 9
4 5 6
1 2 3];
[uniquerow, ~, rowidx] = unique(A, 'rows');
noccurrences = accumarray(rowidx, 1)
Returns:
noccurrences =
2
3
2
1
As expected
I would recommend #excaza's approach. But just for variety:
A_unique_count = diff([0; find([any(diff(sortrows(A), [], 1), 2); 1])]);

Algorithm to normalize the elements of an array

If an array contains N number of elements (elements can be repeated) and the goal is to make all the elements equal by a +1 on an element and a -1 on another element in each iteration, how can we determine whether it's possible or not to normalize the array? What will be the optimal algorithm to solve the problem?
Ex.
For the array 1 2 3, if I apply +1 on 1 and -1 on 3, the array becomes 2 2 2. That means it's possible in 1 iteration.
For the array 1 2 1, it's not possible to make all the elements equal.
First, since you're not disturbing the sum by each iteration, since you're increasing one number and decreasing another, the optimal target value is going to be the average.
If this average is a whole number, you should be able to achieve it with the iterations, however if the average is a fractional number then you will not be able to achieve it.
The number of steps is going to be the sum of the distances between each number and the target, divided by 2.
Every iteration pick one number above target and one below and apply the operations to them.
PS! As per commented, if all you want is answers to the following two questions:
Can it be done
What will the value be
Then the answers are:
Yes, provided the average number is a whole number
The value repeated in the whole array is the average number
Anyway, if you want the actual operations getting from the input to the target values, here's a longer example:
1 2 3 4 5 6 7 = 28, 28/7 = 4 (optimal target)
+ -
2 2 3 4 5 6 6
+ -
3 2 3 4 5 6 5
+ -
4 2 3 4 5 6 4
+ -
4 3 3 4 5 5 4
+ -
4 4 3 4 5 4 4
+ -
4 4 4 4 4 4 4
6 steps, let's total the distances from the first number:
1 2 3 4 5 6 7
3 2 1 0 1 2 3 = 12, divided by 2 = 6
Here's the example from the comments on the question:
1 9 10 12 3 7 = 42 / 6 = 7 (optimal target)
Distances:
1 9 10 12 3 7
6 2 3 5 4 0 = 20, divided by 2 = 10 (steps)
1 9 10 12 3 7
+ - step 1
2 8 10 12 3 7
+ - step 2
3 7 10 12 3 7
+ - step 3
4 7 9 12 3 7
+ - step 4
5 7 8 12 3 7
+ - step 5
6 7 7 12 3 7
+ - step 6
7 7 7 11 3 7
- + step 7
7 7 7 10 4 7
- + step 8
7 7 7 9 5 7
- + step 9
7 7 7 8 6 7
- + step 10
7 7 7 7 7 7
Here is a more pseudo-code like algorithm description:
Calculate SUM of all the elements
COUNT all the elements
If AVERAGE (SUM/COUNT) is not whole number, solution is not possible to achieve
STEPS = SUM(ABS(numberN - AVERAGE))/2
Each iteration, pick one number below AVERAGE and one above
Apply + operation to number below and - operation to number above
Repeat steps 5 and 6 until target achieved

matlab get neighbours on matrix

I have a simple matrix:
1 2 3 4
5 6 7 8
8 9 10 11
12 13 14 15
I need to loop through each element and build a new matrix with 3 of its surrounding elements (the one to the right, bottom right and bottom). So I will end up with an array like so:
1 2 6 5
2 3 7 6
3 4 8 7
I managed to do this but when I need to jump to the row below I can't seem to figure out how to do it. for the next row it should be:
5 6 9 8
6 7 10 9
...
Any ideas?
[m n] = size(A);
[jj ii] = ndgrid(1:m-1, 1:n-1); %// rows and columns except last ones
kk = sub2ind([m n], ii(:),jj(:)); %// to linear index
B = [ A(kk) A(kk+m) A(kk+m+1) A(kk+1) ] %// pick desired values with linear index
In your example:
B =
1 2 6 5
2 3 7 6
3 4 8 7
5 6 9 8
6 7 10 9
7 8 11 10
8 9 13 12
9 10 14 13
10 11 15 14
My favourite bsxfun being put to work here -
[M,N] = size(A); %// A is Input
ind = bsxfun(#plus,[1:M-1],[(0:N-2).*M]') %//'
out = A(bsxfun(#plus,ind(:),[0 M M+1 1])) %// Desired output
Output using the sample input from question -
out =
1 2 6 5
2 3 7 6
3 4 8 7
5 6 9 8
6 7 10 9
7 8 11 10
8 9 13 12
9 10 14 13
10 11 15 14

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