Get all columns of matrix except some indices - matlab

I have a matrix x and an index vector p. Now I want to select all the columns in x except the columns in p.
Example:
x = [12,11,33,33;22,44,33,44;33,22,55,32]
p = [2,4]
then it should return
out = [12,33;22,33;33,55]

Use setdiff and end
>> x(:,setdiff(1:end,p))
ans =
12 33
22 33
33 55

One way:
out = x;
out(:,p) = []
another way:
out = x(:,setxor(p,1:size(x,2)))
%// ore inspired by Mohsen Nosratinia
out = x(:,setxor(p,1:end))
and another one:
mask(size(x,2)) = 0
mask(p) = 1
out = x(:,~mask)

There are many ways to do this, but a simple one is:
y = x; %// Create copy of x
y(:,p) = [] %// Remove columns p
Or, maybe you prefer to use sparse?
x(:,~sparse(p,1,1));
Or how about accumarray?
x(:,~accumarray(p.',1))

Related

Assign multiple variables at once in MATLAB [duplicate]

Here's an example of what I'm looking for:
>> foo = [88, 12];
>> [x, y] = foo;
I'd expect something like this afterwards:
>> x
x =
88
>> y
y =
12
But instead I get errors like:
??? Too many output arguments.
I thought deal() might do it, but it seems to only work on cells.
>> [x, y] = deal(foo{:});
??? Cell contents reference from a non-cell array object.
How do I solve my problem? Must I constantly index by 1 and 2 if I want to deal with them separately?
You don't need deal at all (edit: for Matlab 7.0 or later) and, for your example, you don't need mat2cell; you can use num2cell with no other arguments::
foo = [88, 12];
fooCell = num2cell(foo);
[x y]=fooCell{:}
x =
88
y =
12
If you want to use deal for some other reason, you can:
foo = [88, 12];
fooCell = num2cell(foo);
[x y]=deal(fooCell{:})
x =
88
y =
12
Note that deal accepts a "list" as argument, not a cell array. So the following works as expected:
> [x,y] = deal(88,12)
x = 88
y = 12
The syntax c{:} transforms a cell array in a list, and a list is a comma separated values, like in function arguments. Meaning that you can use the c{:} syntax as argument to other functions than deal. To see that, try the following:
> z = plus(1,2)
z = 3
> c = {1,2};
> z = plus(c{:});
z = 3
To use the num2cell solution in one line, define a helper function list:
function varargout = list(x)
% return matrix elements as separate output arguments
% example: [a1,a2,a3,a4] = list(1:4)
varargout = num2cell(x);
end
What mtrw said. Basically, you want to use deal with a cell array (though deal(88,12) works as well).
Assuming you start with an array foo that is n-by-2, and you want to assign the first column to x and the second to y, you do the following:
foo = [88,12;89,13;90,14];
%# divide the columns of foo into separate cells, i.e. do mat2cell(foo,3,[1,1])
fooCell = mat2cell(foo,size(foo,1),ones(size(foo,2),1));
[x,y] = deal(fooCell{:});
DEAL is really useful, and really confusing. foo needs to be a cell array itself, I believe. The following seems to work in Octave, if I remember correctly it will work in MATLAB as well:
> foo = {88, 12}
foo =
{
[1,1] = 88
[1,2] = 12
}
> [x,y] = deal(foo{:})
x = 88
y = 12
I cannot comment other answers, so separate addition.
you can use deal(88,12) if you are starting from scalars
deal can be used as a one-liner for non-scalars as well, of course if you already have them in separate variables, say:
a = 123;
b = rand(3);
c = {a, b};
d = struct('field','val')
and now you deal them with one line:
>> [x,y,z,w] = deal(a,b,c,d)
x =
123
y =
0.6370 0.2165 0.6711
0.2945 0.8803 0.2705
0.7633 0.1537 0.0767
z =
[123] [3x3 double]
w =
field: 'val'
However, if they are packed in one variable, you can only deal them if they are in a cell or structure array - with deal(X{:}) for cell array and deal(S.field) for structure array. (In the latter case only one field is dealt, but from all structures in array.) With Matlab v.7+ you can use X{:} and S.field without deal, as noted in other answers.
Create a function arr2vars for convenience
function varargout = arr2vars(arr)
% Distribute elements over variables
N = numel(arr);
if nargout ~= N
error('Number of outputs does not match number of elements')
end
for k = 1:N
varargout{k} = arr(k);
end
You can use it then like this
[~,roi] = imcrop(im);
[x,w,y,h] = arr2vars(roi);
You might be looking for
>>> foo = [88, 12];
>>> [x, y] = deal(foo(1), foo(2))
resulting in
x =
88
y =
12
So you have a working one-liner.
There is an easier way.
x = foo (1, 1)
y = foo (1, 2)
Provides
>> x
x =
88
>> y
y =
12
Full documentation at Mathworks.

What is the meaning of the following matlab notation?

I want to write this matlab code in python but I do not know what LEV(1:n+1:n^2) = 0; or LEV(i,:) means. Can anyone explain me what are this notation? Thank you!
function A = ILU_p(A,p)
n = length(A);
LEV = inf(n);
LEV(find(A)) = 0;
LEV(1:n+1:n^2) = 0;
for i = 2:n
for k = 1:i-1
if LEV(i,k) > p
continue
end
A(i,k) = A(i,k) / A(k,k);
A(i,k+1:n) = A(i,k+1:n) - A(i,k) * A(k,k+1:n);
LEV(i,k+1:n) = min([LEV(i,k+1:n); LEV(i,k) + LEV(k,k+1:n) + 1]);
end
A(i,find(LEV(i,:)>p)) = 0;
end
The below sets up a vector of values to be used in an index. If n=10 then the below would yield a row vector of [1 12 23 34 45 56 67 78 89 100]
1:n+1:n^2
Since LEV is set up as an nxn matrix and the above row vector picks up the diagonal elements, i.e., LEV(1) = LEV(1,1), LEV(12) = LEV(2,2), etc.
LEV(i,:) is MATLAB's shorthand for referencing all columns in row i.

Create index vector efficiently in matlab

Given three positive integers x,y, and z, such that x>y. What is the most efficient way to create the following vector:
1,2,3,..,x-y,x+1,x+2,x+3,..,2x-y,2x+1,2x+2,2x+3,..,3x-y,3x+1,...,..,zx+1,zx+2,zx+3,..,zx-y
This problem can be seen as a matrix, in which you add (1:x-y) to the various rows, and (0:z)*x) to the various columns. This can be done efficiently using bsxfun. To obtain the final result, you have to flatten the matrix to a column vector with (:) and transpose it to get the desired row vector:
>> x = 10; y = 7; z = 3;
>> vector = bsxfun(#plus, (1:(x-y)).', (0:z)*x);
>> vector = vector(:).'
vector =
1 2 3 11 12 13 21 22 23 31 32 33
Using matrix multiplication (column vector x row vector), an alternative solution is:
x = 10; y = 7; z = 3;
a = (1:x-y).'*ones(1,x-y) + ones(x-y,1)*(0:x:x*(z-1));
a = a(:).';

select a range of values from a matrix and swap them

I have a matrix and i want to select a range of elements.
for example i want to select all the elements that are lower than 182 and swap/change them.
does someone know an easy way or command to do this in matlab ?
thanx
Since you say "swap", I understand you mean a vector, not a matrix. You can do it as follows:
x = [ 1 34 66 22 200 55 301 ]; % data
[ values, ind ] = find(x<182);
x(ind) = x(ind(end:-1:1));
To simply replace them by another value such as NaN, do as follows. Note that this works also for matrices:
x = [ 1 34 66 22 200 55 301 ]; % data
x(x<182) = NaN;
Such things can usually be accomplished via logical indexing:
A = randn(1,100);
B = randn(size(A));
test = (A>1|A<0); % For example, values that are greater than 1 or less than 0
A(test) = B(test);
or another example:
A = randn(1,100);
test = (A>1|A<0);
A(test) = randn(1,nnz(test));
or another:
A = randn(1,100);
A(A>1|A<0) = NaN;
You may use loop like this:
for i = 1:length(matrix(:,1))
for j = 1:length(matrix(1,:))
if matrix(i,j) < 182
matrix(i,j) = NaN;
end
end
end

Matlab: Find values of a matrix between desired bounds

I have a matrix sorted in ascending order.
S = 25;
RT = zeros(S,2);
for i = 1:S;
for j = 1:i;
R = i *j;
T = R + j;
RT(j,:) = [R T];
end
end
sortRT = sortrows(RT, [1 2]);
disp(sortRT);
I want to find the sortRT elements which values is lower than 500 (for R) and 490 (for T) per column and place these values inside a matrix. Is it possible?
Just use find:
idx = find(sortRT(:,1)<500 & sortRT(:,2)<490)
idx' =
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
These are the rows where both R<500 and T<490. You can of course separate these two:
idxR500 = find(sortRT(:,1)<500);
idxT490 = find(sortRT(:,2)<490);
If you're just going to copy elements or rows, then find isn't even necessary and you can use logical indexing:
R500 = sortRT(find(sortRT(:,1)<500) , 1);
is the same as
R500 = sortRT(sortRT(:,1)<500 , 1);
This copies elements of the first column, if you want to copy the whole row, use the colon operator:
R500 = sortRT(sortRT(:,1)<500 , :);