Nested loop and conditional statement (Matlab) - matlab

If you have a random matrix, for example a 5x5:
A(i,j) = (5 4 3 2 1
4 3 2 1 0
5 4 3 2 1
4 3 2 1 0
5 4 3 2 1)
And a second array:
B(1,j) = (4 5 6 7 8)
How can I then assign values of B to A if this only needs to be done when the value of B(1,j) is larger than any of the values from a certain colomn of A?
For example, B(1,1) = 4 and in the first colomn of A it is larger than A(1,1), A(3,1) and A(5,1), so these must be replaced by 4. In the second colomn, nothing needs to be replaced, etc.
Thanks already!

You can do this without any explicit looping using bsxfun:
A = [5 4 3 2 1
4 3 2 1 0
5 4 3 2 1
4 3 2 1 0
5 4 3 2 1];
B = [4 5 6 7 8];
A = bsxfun(#min,A,B);
Result:
A =
4 4 3 2 1
4 3 2 1 0
4 4 3 2 1
4 3 2 1 0
4 4 3 2 1
In later versions of MATLAB (2016b and later) you can even omit the bsxfun and get the same result.
A = min(A,B);

Matlab "find" may be of use to you.
https://www.mathworks.com/help/matlab/matlab_prog/find-array-elements-that-meet-a-condition.html
If you aren't concerned about speed or efficiency, you could also set up a two nested for loops with a condition (i.e. an if) statement comparing the values of A and B.
If you only interested in column wise comparison to B, you could use the increment of the outer loop in the inner loop.
for i,...
for j,...
if B(1,i) > A(j,i)
A(j,i)=B(i,j)

Related

Element-wise concatenation of 2 vectors in kdb+

Given 2 vectors A and B, I want to concatenate each element of A with each element of B. For example if A and B were as follows:
A: 0 1 2
B: 3 4 5
then the output should be (0 3;1 4; 2 5)
Joining the two vectors using the each (each-both in this case) iterator returns your desired output.
q)0N!A,'B
(0 3;1 4;2 5)
0 3
1 4
2 5
You could also instantiate through the following
(A;B) to create a 2x3 matrix which can be flipped to get what you require
q)A:0 1 2
q)B:3 4 5
q)(A;B)
0 1 2
3 4 5
q)flip (A;B)
0 3
1 4
2 5

MATLAB - Frequency of an array element with a condition

I need some help please. I have an array, as shown below, 6 rows and 5 columns, none of the elements in any one row repeats. The elements are all single digit numbers.
I want to find out, per row, when a number, let's say 1 appears, I want to keep of how often the other numbers of the row appear. For example, 1 shows up 3 times in rows one, three and five. When 1 shows up, 2 shows up one time, 3 shows up two times, 4 shows up two times, 5 shows up one time, 6 shows up two times, 7 shows up one time, 8 shows up three times, and 9 shows up zero times. I want to keep a vector of this information that will look like, V = [3,1,2,2,1,2,1,3,0], by starting with a vector like N = [1,2,3,4,5,6,7,8,9]
ARRAY =
1 5 8 2 6
2 3 4 6 7
3 1 8 7 4
6 5 7 9 4
1 4 3 8 6
5 7 8 9 6
The code I have below does not give the feedback I am looking for, can someone help please? Thanks
for i=1:length(ARRAY)
for j=1:length(N)
ARRAY(i,:)==j
V(j) = sum(j)
end
end
Using indices that is in A creae a zero and one 6 * 9 matrix that [i,j] th element of it is 1 if i th row of A contains j.
Then multiply the zero and one matrix with its transpose to get desirable result:
A =[...
1 5 8 2 6
2 3 4 6 7
3 1 8 7 4
6 5 7 9 4
1 4 3 8 6
5 7 8 9 6]
% create a matrix with the size of A that each row contains the row number
rowidx = repmat((1 : size(A,1)).' , 1 , size(A , 2))
% z_o a zero and one 6 * 9 matrix that [i,j] th element of it is 1 if i th row of A contains j
z_o = full(sparse(rowidx , A, 1))
% matrix multiplication with its transpose to create desirable result. each column relates to number N
out = z_o.' * z_o
Result: each column relates to N
3 1 2 2 1 2 1 3 0
1 2 1 1 1 2 1 1 0
2 1 3 3 0 2 2 2 0
2 1 3 4 1 3 3 2 1
1 1 0 1 3 3 2 2 2
2 2 2 3 3 5 3 3 2
1 1 2 3 2 3 4 2 2
3 1 2 2 2 3 2 4 1
0 0 0 1 2 2 2 1 2
I don't understand how you are approaching the problem with your sample code but here is something that should work. This uses find, any and accumarray and in each iteration for the loop it will return a V corresponding to the ith element in N
for i=1:length(N)
rowIdx = find(any(A == N(i),2)); % Find all the rows contain N(j)
A_red = A(rowIdx,:); % Get only those rows
V = [accumarray(A_red(:),1)]'; % Count occurrences of the 9 numbers
V(end+1:9) = 0; % If some numbers don't exist place zeros on their counts
end

Unique combinations of a beaded necklace [duplicate]

This question already has answers here:
Generate all possible combinations of the elements of some vectors (Cartesian product)
(4 answers)
Closed 8 years ago.
So I'm writing a program to determine the unique combinations of a beaded necklace, but I can't seem to get it right. The rules are you can't have the same necklace forwards and backwards, and you can't have the same necklace with one bead being slid around to the other end. I've attached some pictures to clarify.
I wrote the code for it, and I thought I had achieved what I was trying to do, but it's not working correctly.
n = [1 2 3 4 2 4];
% green = 1
% blue = 2
% yellow = 3
% red = 4
p = perms(n);
total = max(size(p));
for i = 1:max(size(p))
q = p;
q(i) = [];
for j = 1:max(size(q))
if isequal(p(i),fliplr(q(j)))
total = total - 1;
elseif isequal(p(i),circshift(q(j),[1,1]))
total = total - 1;
elseif isequal(p(i),circshift(q(j),[length(q(j))-1,length(q(j))-1]))
total = total - 1;
end
disp(total)
end
end
Logically, this makes sense to me, but I could just be crazy.
If the problem size is small, you can vectorize all the comparisons (using bsxfun):
n = [1 2 3 4 2 4];
%// green = 1
%// blue = 2
%// yellow = 3
%// red = 4
N = numel(n);
p = perms(n).'; %'// generate all permutations
p2 = NaN([size(p) N+1]); %// this will store permutations with flips and shifts
p2(:,:,1) = p; %// original
p2(:,:,2) = flipud(p); %// flips
for k = 1:N-1
p2(:,:,2+k) = circshift(p,k); %// circular shifts
end
eqElem = bsxfun(#eq, p, permute(p2, [1 4 2 3]));
eqMat = squeeze(any(all(eqElem, 1), 4)); %// 1 if equal
remove = any(tril(eqMat, -1), 1); %// remove permutations that are "similar"
%// to a previous one, where "similar" means "equal up to circular shifts or
%// flips"
result = p(:,~remove).'; %'// all valid arrangements; one per row
resultNum = size(result, 1); %// number of arrangements
Results:
result =
1 3 2 2 4 4
1 3 2 4 4 2
1 3 2 4 2 4
1 3 4 2 2 4
1 3 4 2 4 2
1 3 4 4 2 2
1 2 3 2 4 4
1 2 3 4 2 4
1 2 3 4 4 2
1 2 2 3 4 4
1 2 2 4 4 3
1 2 2 4 3 4
1 2 4 3 2 4
1 2 4 3 4 2
1 2 4 2 3 4
1 2 4 2 4 3
1 2 4 4 2 3
1 2 4 4 3 2
1 4 4 3 2 2
1 4 4 2 2 3
1 4 4 2 3 2
1 4 3 4 2 2
1 4 3 2 2 4
1 4 3 2 4 2
1 4 2 3 2 4
1 4 2 3 4 2
1 4 2 2 3 4
1 4 2 2 4 3
1 4 2 4 2 3
1 4 2 4 3 2
resultNum =
30
You should do p = unique(p,'rows') before any loops. To see why, call perms([1 1 1]) at the command line.
There are a few issues here:
1) p, the perms, is a 2D matrix, so to get each perm you need to do p(i,:) to get the row. p(i) is just a single number.
2) You don't remove wrong answers from your list, so you will check against them twice. For example, say the first in the list is [1 2 3 4 2 4]; and the second is [4 2 4 3 2 1];. The fliplr check will compare these two combinations twice, once in the first loop around, once in the second.
3) If you want to make sure that any permutation which is a rotation is excluded (not just moving one bead around), you'll need some more circshift.
Consider using ismember with rows option again to compare a single row (e.g. a flipped version of the row you're checking) to an entire matrix.

How to subtract every nth column in Matlab

If I have an arbitrary n*m matrix called data and I would like to take differences of the matrix using gradually bigger steps.
The first case would have a first column equal to data(:,2)-data(:,1), the next column would be data(:,3)-data(:,2) and so on. This can be done with the following function.
data = diff(data,1,2)
Similarly I would also like to take differences based of every second column, so that the first entry would be data(:,3)-data(:,1) and the next data(:,5)-data(:,3) and so on.
This can't be done with diff, but is there any other function or method that can do it without resorting to looping?
I need to do the same thing for every n value up to 50.
Use column indexing to select the "right" columns and then use your favourite diff -
A = randi(9,4,9) %// Input array
stepsize = 2; %// Edit this for a different stepsize
out = diff(A(:,1:stepsize:end),1,2)
Output -
A =
8 9 9 8 3 2 6 8 7
2 5 5 7 5 3 9 6 3
2 7 7 2 4 1 2 4 1
6 2 1 5 4 9 9 3 7
out =
1 -6 3 1
3 0 4 -6
5 -3 -2 -1
-5 3 5 -2
I just wrote a simple wrapper function for the purpose.
function [ out ] = diffhigh( matrix, offset )
matrix_1 = matrix(:,(offset+1):size(matrix,1));
matrix_2 = matrix(:, 1:(size(matrix,1)-offset));
out = matrix_1 - matrix_2;
end
>> a
a =
3 5 1 2 4
1 2 3 4 5
1 4 5 3 2
1 2 4 3 5
2 1 5 3 4
>> diffhigh(a, 2)
ans =
-2 -3 3
2 2 2
4 -1 -3
3 1 1
3 2 -1
>> diffhigh(a, 3)
ans =
-1 -1
3 3
2 -2
2 3
1 3

How to flip specific parts of a matrix

I am trying to flip certain parts of a matrix. I can explain better by example. Let's say that I have a matrix
M = [ 1 3 6;
1 2 4;
1 7 1;
2 9 0;
2 8 3;
2 4 2;
2 3 1;
3 6 5;
3 4 5;
3 1 9;
4 2 4;
4 8 6 ]
What I'd like to do here is take any rows with an even number in the first column, and flip the third column elements. The end result would look like this:
1 3 6
1 2 4
1 7 1
2 9 1 *
2 8 2 *
2 4 3 *
2 3 0 *
3 6 5
3 4 5
3 1 9
4 2 6 *
4 8 4 *
Note the rows marked with a star have had the elements of the third column flipped upside-down. The problem I'm having is going through each row like in a for-loop you cannot flip an entire set of rows.
Thanks in advance for any help.
Another time accumarray is the way to go:
A =[ 1 3 6 ;
1 2 4 ;
1 7 1 ;
2 9 0 ;
2 8 3 ;
2 4 2 ;
2 3 1 ;
3 6 5 ;
3 4 5 ;
3 1 9 ;
4 2 4 ;
4 8 6 ]
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} ); %// get groups according to
%// first column and flip it
C = vertcat(C{:}); %// cell array returned,
%// transform to matrix
mask = ~mod(A(:,1),2); %// mask for even numbers
A(mask,3) = C(mask); %// replace masked values of 3rd column with flipped ones
returns:
A =
1 3 6
1 2 4
1 7 1
2 9 1
2 8 2
2 4 3
2 3 0
3 6 5
3 4 5
3 1 9
4 2 6
4 8 4
Certainly slower, but just for fun in two lines:
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} );
A(~mod(A(:,1),2),3) = getfield( vertcat(C{:}), {~mod(A(:,1),2)});
%// well no, I won't explain it...
Edit: I assumed your first column just contains integers!
I would suggest you break the problem down into stages, something like so:
Identify blocks you wish to flip
Extract them
Flip them
Replace them
You can identify a set of even numbers using the unique and mod functions, then use a for loop over them and use logical indexing to pull/replace the blocks.
Here, try this
a = magic(5); % Some data in a 5x5 matrix
b = 1:numel(a); % Indices of <a>
Rearrange b however you want, then do a=a(b) to reassign a based on the reassigned indices of b. For example, the following code
disp(a(b));
would just return the elements of a in their original order. For your application this code should work:
a = <your matrix data>
b = 1:numel(a);
b = [b(1:27) fliplr(b(28:31)) b(32:34) fliplr(b(35:36))] % Change this part
a = reshape(a(b),size(a))
You should change b based on whatever you need it to do.